Эффективность 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 ответа
Давайте посмотрим, что делают различные звонки, которые вы предоставили:
emplace_back(mystring)
: Это конструкция на месте нового элемента с любым аргументом, который вы указали. Так как вы указали lvalue, эта конструкция на месте фактически является копируемой конструкцией, т.е. это то же самое, что и вызовpush_back(mystring)
push_back(std::move(mystring))
: Это вызывает перемещение-вставку, которая в случае std::string является встроенной конструкцией перемещения.emplace_back(std::move(mystring))
: Это снова конструкция на месте с указанными вами аргументами. Поскольку этот аргумент является rvalue, он вызывает Move-конструкторstd::string
то есть это движение-конструкция на месте, как в 2.
Другими словами, если вызывается с одним аргументом типа T, будь то значение rvalue или lvalue, emplace_back
а также push_back
эквивалентны.
Тем не менее, для любого другого аргумента (-ов), emplace_back
выигрывает гонку, например, с char const*
в vector<string>
:
emplace_back("foo")
звонкиstring::string(char const*)
для строительства на месте.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 для уже созданных элементов.