En C ++ 11 emplace_back()
generalmente se prefiere (en términos de eficiencia) push_back()
porque permite la construcción en el lugar, pero ¿sigue siendo así cuando se usa push_back(std::move())
con un objeto ya construido?
Por ejemplo, ¿ emplace_back()
todavía se prefiere en casos como el siguiente?
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)
Además, ¿hay algún beneficio en el ejemplo anterior de hacer en su lugar:
myvector.emplace_back(std::move(mystring));
¿O la mudanza aquí es completamente redundante o no tiene ningún efecto?
c++11
move-semantics
push-back
emplace
Alboroto
fuente
fuente
myvector.emplace_back(mystring);
copia y no se mueve. Los otros dos se mueven y deberían ser equivalentes.Respuestas:
Veamos qué hacen las diferentes llamadas que proporcionó:
emplace_back(mystring)
: Esta es una construcción in situ del nuevo elemento con cualquier argumento que haya proporcionado. Dado que proporcionó un lvalue, esa construcción en el lugar de hecho es una construcción de copia, es decir, esto es lo mismo que llamarpush_back(mystring)
push_back(std::move(mystring))
: Esto llama a la inserción de movimiento, que en el caso de std :: string es una construcción de movimiento en el lugar.emplace_back(std::move(mystring))
: Esta es nuevamente una construcción en el lugar con los argumentos que proporcionó. Dado que ese argumento es un valor r, llama al constructor de movimiento destd::string
, es decir, es una construcción de movimiento en el lugar como en 2.En otras palabras, si se llama con un argumento de tipo T, ya sea rvalue o lvalue,
emplace_back
ypush_back
son equivalentes.Sin embargo, para cualquier otro argumento,
emplace_back
gana la carrera, por ejemplo con achar const*
en avector<string>
:emplace_back("foo")
requierestring::string(char const*)
construcción in situ.push_back("foo")
primero tiene que llamarstring::string(char const*)
a la conversión implícita necesaria para que coincida con la firma de la función, y luego una inserción de movimiento como en el caso 2. anterior. Por lo tanto es equivalente apush_back(string("foo"))
fuente
s
puede definirse como una referencia rvalue que se une solo a rvalues, pero dentro defoo
,s
hay un lvalue.Emplace_back obtiene una lista de referencias de rvalue e intenta construir un elemento contenedor directamente en su lugar. Puede llamar a emplace_back con todos los tipos que admiten los constructores de elementos de contenedor. Cuando se llama a emplace_back para parámetros que no son referencias de rvalue, "recurre" a las referencias normales y al menos se llama al constructor de copia cuando el parámetro y los elementos del contenedor son del mismo tipo. En su caso, 'myvector.emplace_back (mystring)' debería hacer una copia de la cadena porque el compilador no pudo saber que el parámetro myvector es movible. Así que inserte std :: move lo que le da el beneficio deseado. El push_back debería funcionar tan bien como emplace_back para elementos ya construidos.
fuente