Эффективность С++ 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>
:
-
emplace_back("foo")
вызывает string::string(char const*)
для встроенной конструкции.
-
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 для уже построенных элементов.