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


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

например,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 64

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*) на месте строительства.

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

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