Я немного сбит с толку относительно разницы между push_back
и emplace_back
.
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);
Поскольку существует push_back
перегрузка, принимающая ссылку на rvalue, я не совсем понимаю, для чего это emplace_back
делается?
template <class _Valty> void emplace_back(_Valty&& _Val)
версия, которая использует универсальную ссылку, которая обеспечивает идеальную пересылку конструкторам сexplicit
одним аргументом.push_back
предпочтительнееemplace_back
? Единственный случай, о котором я могу подумать, это если бы класс был каким-то образом копируемым (T&operator=(constT&)
), но не конструируемым (T(constT&)
), но я не могу понять, почему кто-то когда-либо этого захотел.Ответы:
В дополнение к тому, что посетитель сказал:
Функция,
void emplace_back(Type&& _Val)
предоставляемая MSCV10, не соответствует и избыточна, потому что, как вы заметили, она строго эквивалентнаpush_back(Type&& _Val)
.Но настоящая форма C ++ 0x
emplace_back
действительно полезнаvoid emplace_back(Args&&...)
:;Вместо того, чтобы брать a,
value_type
он принимает список аргументов с переменным числом аргументов, что означает, что теперь вы можете безошибочно пересылать аргументы и непосредственно создавать объект в контейнере без какого-либо временного объекта.Это полезно, потому что независимо от того, насколько умные RVO и семантика перемещения приносят в таблицу, все еще существуют сложные случаи, когда push_back может создавать ненужные копии (или перемещаться). Например, с помощью традиционной
insert()
функции astd::map
вы должны создать временный объект, который затем будет скопирован в astd::pair<Key, Value>
, который затем будет скопирован на карту:Так почему же они не реализовали правильную версию emplace_back в MSVC? На самом деле, это слишком долго меня беспокоило, поэтому я задал тот же вопрос в блоге по Visual C ++ . Вот ответ Стефана Т Лававея, официального сопровождающего реализации стандартной библиотеки Visual C ++ в Microsoft.
Это понятное решение. Каждый, кто хотя бы один раз пытался эмулировать шаблон вариации с ужасными приемами препроцессора, знает, как отвратительно получается это.
источник
pair<const int,Complicated>
не имеет конструктора, который принимает int, другой int, double и в качестве 4-го параметра строку. Тем не менее, вы можете напрямую создать эту пару объектов, используя его кусочно-конструктор. Синтаксис будет разным, конечно:m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
emplace_back
если она была реализована в Visual C ++ при добавлении шаблонов с переменными параметрамиemplace_back
не должен принимать аргумент типаvector::value_type
, а вместо этого использовать переменные аргументы, которые передаются в конструктор добавляемого элемента.Можно передать a,
value_type
который будет перенаправлен в конструктор копирования.Поскольку он передает аргументы, это означает, что если у вас нет значения rvalue, это все равно означает, что контейнер будет хранить «скопированную» копию, а не перемещенную копию.
Но вышеупомянутое должно быть идентично тому, что
push_back
делает. Скорее всего, он предназначен для случаев использования, таких как:источник
s
в области, разве это не опасно?vec.emplace_back("Hello")
будет работать, так какconst char*
аргумент будет перенаправлен вstring
конструктор. В этом весь смыслemplace_back
.std::vector
. Пустоеstd::vector
является допустимым состоянием, но вы не можете вызватьfront()
его. Это означает, что любая функция, которая не имеет предварительных условий, все еще может быть вызвана (и деструкторы никогда не могут иметь предварительных условий).Оптимизация для
emplace_back
может быть продемонстрирована в следующем примере.Ибо
emplace_back
конструкторA (int x_arg)
будет называться. И дляpush_back
A (int x_arg)
называется первым, аmove A (A &&rhs)
потом называется.Конечно, конструктор должен быть помечен как
explicit
, но для текущего примера хорошо бы удалить явность.вывод:
источник
emplace_back
противpush_back
.v.emplace_back(x);
где x явно сконструирован с возможностью перемещения, но только с явной копией. Тот факт, чтоemplace_back
«неявно» явный, заставляет меня думать, что моя функция перехода для добавления, вероятно, должна бытьpush_back
. Мысли?a.emplace_back
второй раз, будет вызван конструктор перемещения!Хороший код для push_back и emplace_back показан здесь.
http://en.cppreference.com/w/cpp/container/vector/emplace_back
Вы можете видеть операцию перемещения на push_back, а не на emplace_back.
источник
emplace_back
соответствующая реализация передаст аргументыvector<Object>::value_type
конструктору при добавлении в вектор. Напомню, что Visual Studio не поддерживала шаблоны с переменными значениями, но с помощью шаблонов с различными параметрами будет поддерживаться в Visual Studio 2013 RC, поэтому я предполагаю, что будет добавлена соответствующая подпись.С
emplace_back
, если вы перенаправляете аргументы непосредственно вvector<Object>::value_type
конструктор, вам не нужно, чтобы типemplace_back
, строго говоря, был подвижным или копируемым для функции. В данномvector<NonCopyableNonMovableObject>
случае это бесполезно, посколькуvector<Object>::value_type
для роста требуется копируемый или подвижный тип.Но обратите внимание, что это может быть полезно
std::map<Key, NonCopyableNonMovableObject>
, поскольку после выделения записи на карте ее больше не нужно перемещать или копировать, в отличие отvector
, что означает, что вы можетеstd::map
эффективно использовать сопоставленный тип, который нельзя ни копировать, ни копировать. подвижна.источник
Еще один в случае списков:
источник
Конкретный вариант использования для
emplace_back
: Если вам нужно создать временный объект, который затем будет помещен в контейнер, используйтеemplace_back
вместоpush_back
. Это создаст объект на месте внутри контейнера.Ноты:
push_back
в приведенном выше случае создадим временный объект и переместим его в контейнер. Однако используемая для на месте конструкцияemplace_back
будет более производительной, чем создание и перемещение объекта (что обычно требует некоторого копирования).emplace_back
вместоpush_back
всех случаев без особых проблем. (См. Исключения )источник