В 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));
Или этот шаг здесь полностью избыточен или не имеет никакого эффекта?
myvector.emplace_back(mystring);
копирует и не перемещается. Два других хода должны быть эквивалентными.Ответы:
Давайте посмотрим, что делают разные вызовы, которые вы предоставили:
emplace_back(mystring)
: Это создание нового элемента на месте с любым аргументом, который вы указали. Поскольку вы указали lvalue, эта конструкция на месте фактически является копией, т.е. это то же самое, что и вызовpush_back(mystring)
push_back(std::move(mystring))
: Это вызывает вставку перемещения, которая в случае std :: string является конструкцией перемещения на месте.emplace_back(std::move(mystring))
: Это снова внутренняя конструкция с указанными вами аргументами. Поскольку этот аргумент является rvalue, он вызывает конструктор перемещенияstd::string
, т.е. это конструкция перемещения на месте, как в 2.Другими словами, если вызывается с одним аргументом типа T, будь то RValue или именующее выражение,
emplace_back
иpush_back
эквивалентны.Однако для любого другого аргумента (ов)
emplace_back
выигрывает гонка, например, с achar const*
вvector<string>
:emplace_back("foo")
требует строительстваstring::string(char const*)
на месте.push_back("foo")
сначала нужно вызватьstring::string(char const*)
неявное преобразование, необходимое для соответствия сигнатуре функции, а затем вставить перемещение, как в случае 2. выше. Следовательно, это эквивалентноpush_back(string("foo"))
источник
s
может быть определена как RValue ссылка , что связывается только с rvalues, но внутриfoo
,s
это именующий.Emplace_back получает список ссылок rvalue и пытается построить элемент контейнера прямо на месте. Вы можете вызвать emplace_back со всеми типами, которые поддерживаются конструкторами элементов контейнера. Когда вызывается emplace_back для параметров, которые не являются ссылками на rvalue, он «возвращается» к обычным ссылкам и, по крайней мере, вызывается конструктор копирования, когда параметр и элементы контейнера имеют один и тот же тип. В вашем случае myvector.emplace_back (mystring) должен сделать копию строки, потому что компилятор не мог знать, что параметр myvector подвижен. Итак, вставьте std :: move, что дает желаемое преимущество. Push_back должен работать так же, как emplace_back для уже построенных элементов.
источник