Эффективность С++ 11 push_back() с помощью std:: move versus emplace_back() для уже построенных объектов

В С++ 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));

или это движение здесь полностью избыточно или не имеет эффекта?

Ответ 1

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

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

  • push_back(std::move(mystring)): Это вызывает перемещение-вставку, которое в случае std::string ist-in-place move-construction.

  • 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"))

Ответ 2

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