Estoy un poco confundido con respecto a la diferencia entre push_back
y emplace_back
.
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);
Como hay una push_back
sobrecarga tomando una referencia de valor no entiendo en qué se emplace_back
convierte el propósito .
template <class _Valty> void emplace_back(_Valty&& _Val)
versión que toma una referencia universal que proporciona un reenvío perfecto a losexplicit
constructores de un solo argumento.push_back
sea preferibleemplace_back
? El único caso en el que puedo pensar es si una clase fuera de alguna manera copiable (T&operator=(constT&)
) pero no construible (T(constT&)
), pero no puedo pensar por qué alguien querría eso.Respuestas:
Además de lo que dijo el visitante:
La función
void emplace_back(Type&& _Val)
proporcionada por MSCV10 no es conforme y es redundante, ya que, como ha notado, es estrictamente equivalente apush_back(Type&& _Val)
.Pero la forma real de C ++ 0x
emplace_back
es realmente útil:void emplace_back(Args&&...)
:;En lugar de tomar un
value_type
, toma una lista variada de argumentos, lo que significa que ahora puede reenviar perfectamente los argumentos y construir directamente un objeto en un contenedor sin ningún tipo temporal.Eso es útil porque no importa cuánta inteligencia RVO y movimiento semántico traigan a la mesa, todavía hay casos complicados en los que es probable que un push_back haga copias (o movimientos) innecesarios. Por ejemplo, con la
insert()
función tradicional de astd::map
, debe crear un temporal, que luego se copiará en astd::pair<Key, Value>
, que luego se copiará en el mapa:Entonces, ¿por qué no implementaron la versión correcta de emplace_back en MSVC? En realidad, también me molestó hace un tiempo, así que hice la misma pregunta en el blog de Visual C ++ . Aquí está la respuesta de Stephan T Lavavej, el responsable oficial de la implementación de la biblioteca estándar de Visual C ++ en Microsoft.
Es una decisión comprensible. Todos los que intentaron emular una plantilla variada con trucos horribles del preprocesador saben lo repugnante que es esto.
fuente
pair<const int,Complicated>
no tiene un constructor que tome un int, otro int, un doble y como cuarto parámetro una cadena. Sin embargo, puede construir directamente este objeto par utilizando su constructor por partes. La sintaxis será diferente, por supuesto:m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
emplace_back
siempre que se haya implementado en Visual C ++ cuando se agregaron plantillas variadas: msdn.microsoft.com/en-us/library/hh567368. aspxemplace_back
No debería tomar un argumento de tipovector::value_type
, sino argumentos variados que se envían al constructor del elemento adjunto.Es posible pasar un mensaje
value_type
que se enviará al constructor de la copia.Debido a que reenvía los argumentos, esto significa que si no tiene rvalue, esto significa que el contenedor almacenará una copia "copiada", no una copia movida.
Pero lo anterior debe ser idéntico a lo que
push_back
hace. Probablemente esté destinado a casos de uso como:fuente
s
alcance movido , ¿no es peligroso?vec.emplace_back("Hello")
funcionará, ya que elconst char*
argumento será enviado alstring
constructor. Este es todo el punto deemplace_back
.std::vector
. Un vacíostd::vector
es un estado válido, pero no puede invocarlofront()
. Esto significa que cualquier función que no tenga condiciones previas aún puede llamarse (y los destructores nunca pueden tener condiciones previas).La optimización para
emplace_back
se puede demostrar en el siguiente ejemplo.Para el
emplace_back
constructorA (int x_arg)
se llamará. Y porquepush_back
A (int x_arg)
se llama primero y luegomove A (A &&rhs)
se llama.Por supuesto, el constructor tiene que estar marcado como
explicit
, pero para el ejemplo actual es bueno eliminar lo explícito.salida:
fuente
emplace_back
vspush_back
.v.emplace_back(x);
donde x es explícitamente construible por movimiento pero solo explícitamente construible por copia. El hecho de queemplace_back
sea "implícitamente" explícito me hace pensar que mi función de ir a anexar probablemente debería serlopush_back
. Pensamientos?a.emplace_back
segunda vez, se llamará al constructor de movimiento.Aquí se muestra un buen código para push_back y emplace_back.
http://en.cppreference.com/w/cpp/container/vector/emplace_back
Puede ver la operación de movimiento en push_back y no en emplace_back.
fuente
emplace_back
la implementación conforme reenviará argumentos alvector<Object>::value_type
constructor cuando se agregue al vector. Recuerdo que Visual Studio no admitía plantillas variadas, pero con las plantillas variadas se admitirán en Visual Studio 2013 RC, por lo que supongo que se agregará una firma conforme.Con
emplace_back
, si reenvía los argumentos directamente alvector<Object>::value_type
constructor, no necesita un tipo para ser movible o copiable para laemplace_back
función, estrictamente hablando. En elvector<NonCopyableNonMovableObject>
caso, esto no es útil, ya quevector<Object>::value_type
necesita un tipo copiable o móvil para crecer.Pero tenga en cuenta que esto podría ser útil
std::map<Key, NonCopyableNonMovableObject>
, ya que una vez que asigna una entrada en el mapa, ya no es necesario moverla ni copiarla , a diferencia devector
, lo que significa que puede usarlastd::map
efectivamente con un tipo mapeado que no sea copiable ni móvil.fuente
Uno más en caso de listas:
fuente
Caso de uso específico para
emplace_back
: Si necesita crear un objeto temporal que luego será empujado a un contenedor, use enemplace_back
lugar depush_back
. Creará el objeto en el lugar dentro del contenedor.Notas:
push_back
en el caso anterior creará un objeto temporal y lo moverá al contenedor. Sin embargo, la construcción en el lugar utilizadaemplace_back
sería más eficiente que construir y luego mover el objeto (lo que generalmente implica alguna copia).emplace_back
lugar depush_back
en todos los casos sin muchos problemas. (Ver excepciones )fuente