c++ - push_back - ¿La mejor manera de usar emplace_back para evitar mover la llamada al constructor?
c++ emplace_back (1)
Parece que el constructor de movimiento todavía se llama aunque un prvalue se pasa directamente a emplace_back
Crees que lo haces, pero no lo pasas a la función. Le da un prvalue como argumento, sí, pero lo que emplace_back acepta es un paquete de referencias de reenvío . Una referencia debe referirse a un objeto, por lo que un temporal se materializa y se mueve.
La forma correcta de usar emplace_back es pasarle los argumentos para inicializar el objeto en su lugar . De esa manera, no necesita mover el tipo de elemento del vector (aunque puede que necesite mover / copiar los argumentos).
Acabo de enterarme de la resolución de copias garantizada en C ++ 17 . Según la respuesta a esa pregunta:
Cuando
return T();, esto inicializa el valor de retorno de la función a través de unprvalue. Como esa función devuelve T, no se crea ningún temporal; la inicialización delprvaluesimplemente inicializa directamente el valor de retorno.Lo que hay que entender es que, dado que el valor de retorno es un
prvalue, aún no es un objeto. Es simplemente un inicializador para un objeto, al igual queT()es.
Así que me preguntaba, ¿esto funciona para algo más que:
T f() {return T();}
T t = f();
Así que escribí este código con emplace_back para probarlo:
#include <vector>
#include <iostream>
struct BigObj{
BigObj() = default;
BigObj(int) { std::cout << "int ctor called" << std::endl; }
BigObj(const BigObj&){
std::cout << "copy ctor called" << std::endl;
}
BigObj(BigObj&&){
std::cout << "move ctor called" << std::endl;
}
};
BigObj f(){ return BigObj(2); }
int g(){ return 2; }
int main(){
std::vector<BigObj> v;
v.reserve(10);
std::cout << "emplace_back with rvalue /n";
v.emplace_back(1+1);
std::cout << "emplace_back with f()/n";
v.emplace_back(f());
std::cout << "emplace_back with g()/n";
v.emplace_back(g());
}
Esta es la salida que obtengo (con elision de copia desactivada):
emplace_back with rvalue
int ctor called
emplace_back with f()
int ctor called
move ctor called
emplace_back with g()
int ctor called
Parece que el constructor de movimiento aún se llama, aunque un prvalue se pasa directamente a emplace_back , que pensé que podría usarse para construir directamente un objeto en lugar de usarlo para construir un temporal y luego moverlo.
¿Existe una forma más elegante de evitar la llamada al constructor de movimientos con emplace_back no sea hacer algo como lo que hace la función g() ?