Tengo un método que devuelve un objeto por valor. El método proviene de una biblioteca sobre la que no tengo control. Para el manejo adicional del objeto, quiero seguir trabajando con un unique_ptr en este objeto. Aquí hay un ejemplo:
#include <iostream>
#include <memory>
class Bla {
public:
Bla() { std::cout << "Constructor!\n"; }
~Bla() { std::cout << "Destructor!\n"; }
};
Bla GetBla() {
Bla bla;
return std::move(bla);
}
int main() {
auto bla = std::make_unique<Bla>(GetBla());
}
El ejemplo produce el siguiente resultado:
Constructor!
Destructor!
Destructor!
Destructor!
¿Por qué se llama al destructor de Bla 3 veces aquí? ¿Es correcta la forma en que creo el unique_prt?
c++
unique-ptr
Tobi S.
fuente
fuente
std::move
no mueve nada. Simplemente se lanza de un tipo a otro.std::move
onreturn
es un gran error.Respuestas:
De hecho, hay 3 veces que
Bla
se construye una instancia de .No regrese por movimiento. Simplemente regrese
bla
, en la mayoría de los casos la copia se elidirá.Tenga en cuenta que
make_unique<Bla>
siempre construye una nueva instancia. En este caso, porque está pasando otra instancia, se convierte en una construcción de copia.Una sugerencia de que la construcción de la copia tiene lugar es que su constructor predeterminado se invoca solo una vez, mientras que el destructor se invoca 3 veces. Esto se debe a que en los otros 2 casos se invoca el constructor de copia (o movimiento) implícito (
Bla::Bla(Bla const&)
).fuente
// 2nd construction (return by copy)
no es correcto? El valor devuelto se moverá construido? Vea esto (podría estar equivocado): stackoverflow.com/a/60487169/5735010 .El compilador puede incluso advertirte que
No estoy 100% seguro, pero creo que recibes las tres llamadas de desctructor de:
bla
deGetBla()
GetBla()
después de que se usó enstd::make_unique<Bla>(GetBla());
std::unique_ptr
La forma más fácil es dejar que se
std::make_uniqe
invoque el constructor predeterminado deBla
:Salida
fuente
La forma correcta de crear
unique_ptr
:Sin embargo, su código crea 3 instancias de
Bla
:bla
enGetBla()
función.GetBla()
.make_unique()
crea una instancia más.NOTA:
GetBla()
valor de retorno es una copia del objeto localbla
.GetBla()
devuelvemove
el objeto local ed, se suprime la elisión de copia .fuente
Para ver realmente lo que sucede detrás de escena, puede usar un depurador o definir un constructor de copia . He agregado el constructor de copia en su código. Pruebe el código que figura a continuación:
NOTA:
std::move
no mueve nada Simplemente se convierte delvalue
referencia arvalue
referencia y su objeto devuelto podría haberse construido a través de un constructor de movimiento (y la supresión de copia podría ser suprimida) pero el compilador no declara implícitamente elmove
constructor porque ha definido el destructor (y he agregado el constructor de copia en mi ejemplo)Salidas:
Vea mis comentarios a continuación:
bla
se construye en función aGetBla()
través del constructor predeterminado.GetBla()
función se construye a partir del objeto creado en# 1
.bla
El objeto (construido en # 1) se destruye y se llama a su destructor.std::make_unique<Bla>
llamanew
y luego llama al constructor apropiado y elige elcopy
constructor.fuente