Эффективность push + back() в C++ 11 с std::move и 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));

или движение здесь полностью излишне, или не имеет никакого эффекта?

2 ответа

Решение

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

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

  2. push_back(std::move(mystring)): Это вызывает перемещение-вставку, которая в случае std::string является встроенной конструкцией перемещения.

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

Другие вопросы по тегам