Эффективность C++11 push back() с std:: move против emplace back () для уже построенных объектов

В C++11 emplace_back() обычно предпочтительнее (с точки зрения эффективности)push_back() как это позволяет на месте строительства, но это все еще имеет место при использовании push_back(std::move()) С уже построенным объектом?

например, is emplace_back() по-прежнему предпочтительнее в таких случаях, как следующее?

std::string mystring("hello world");
std::vector<std::string> myvector;

myvector.emplace_back(mystring);
myvector.push_back(std::move(mystring));
// (of course assuming we don't care about using the value of mystring after)

кроме того, есть ли какая-либо польза в приведенном выше примере, чтобы вместо этого делать:

myvector.emplace_back(std::move(mystring));

или перемещение здесь полностью избыточно, или не имеет эффект?

2 ответов


давайте посмотрим, что различные вызовы, которые вы предоставили делать:

  1. emplace_back(mystring): Это конструкция на месте нового элемента с любым аргументом, который вы предоставили. Поскольку вы предоставили lvalue, эта конструкция на месте фактически является копией-конструкцией, т. е. это то же самое, что и вызов push_back(mystring)

  2. push_back(std::move(mystring)): это вызывает Move-insertion, который в случае std::string ist на месте ход строительства.

  3. emplace_back(std::move(mystring)): это снова конструкция на месте с аргументами, которые вы предоставили. Поскольку этот аргумент является rvalue, он вызывает конструктор move std::string, т. е. это конструкция перемещения на месте, как в 2.

другими словами, если вызывается с одним аргументом типа T, будь то rvalue или lvalue, emplace_back и push_back эквивалентны.

однако, для любого другого аргумента(ов),emplace_back выигрывает гонка, например, с char const* на vector<string>:

  1. emplace_back("foo") звонки string::string(char const*) для in-place-конструкции.

  2. push_back("foo") сразу string::string(char const*) для неявного преобразования, необходимого для соответствия сигнатуре функции, а затем вставки перемещения, как в случае 2. выше. Поэтому это эквивалентно push_back(string("foo"))


emplace_back получает список ссылок rvalue и пытается создать элемент контейнера непосредственно на месте. Вы можете вызвать emplace_back со всеми типами, которые поддерживают конструкторы элементов контейнера. При вызове emplace_back для параметров, которые не являются ссылками rvalue, он "возвращается" к обычным ссылкам и, по крайней мере, конструктор копирования вызывается, когда параметр и элементы контейнера имеют один и тот же тип. В вашем случае 'myvector.emplace_back (mystring) ' должен сделать копию из-за строки компилятор не мог знать, что параметр myvector является подвижным. Поэтому вставьте std:: move, что дает вам желаемое преимущество. В push_back должен работать так же, как emplace_back для уже построенных элементов.