Estoy un poco confundido con respecto a la diferencia entre push_backy emplace_back.
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);
Como hay una push_backsobrecarga tomando una referencia de valor no entiendo en qué se emplace_backconvierte 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 losexplicitconstructores de un solo argumento.push_backsea 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_backes 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_backsiempre que se haya implementado en Visual C ++ cuando se agregaron plantillas variadas: msdn.microsoft.com/en-us/library/hh567368. aspxemplace_backNo 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_typeque 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_backhace. Probablemente esté destinado a casos de uso como:fuente
salcance movido , ¿no es peligroso?vec.emplace_back("Hello")funcionará, ya que elconst char*argumento será enviado alstringconstructor. Este es todo el punto deemplace_back.std::vector. Un vacíostd::vectores 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_backse puede demostrar en el siguiente ejemplo.Para el
emplace_backconstructorA (int x_arg)se llamará. Y porquepush_backA (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_backvspush_back.v.emplace_back(x);donde x es explícitamente construible por movimiento pero solo explícitamente construible por copia. El hecho de queemplace_backsea "implícitamente" explícito me hace pensar que mi función de ir a anexar probablemente debería serlopush_back. Pensamientos?a.emplace_backsegunda 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_backla implementación conforme reenviará argumentos alvector<Object>::value_typeconstructor 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_typeconstructor, no necesita un tipo para ser movible o copiable para laemplace_backfunción, estrictamente hablando. En elvector<NonCopyableNonMovableObject>caso, esto no es útil, ya quevector<Object>::value_typenecesita 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::mapefectivamente 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_backlugar depush_back. Creará el objeto en el lugar dentro del contenedor.Notas:
push_backen el caso anterior creará un objeto temporal y lo moverá al contenedor. Sin embargo, la construcción en el lugar utilizadaemplace_backsería más eficiente que construir y luego mover el objeto (lo que generalmente implica alguna copia).emplace_backlugar depush_backen todos los casos sin muchos problemas. (Ver excepciones )fuente