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::moveno mueve nada. Simplemente se lanza de un tipo a otro.std::moveonreturnes un gran error.Respuestas:
De hecho, hay 3 veces que
Blase 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:
bladeGetBla()GetBla()después de que se usó enstd::make_unique<Bla>(GetBla());std::unique_ptrLa forma más fácil es dejar que se
std::make_uniqeinvoque el constructor predeterminado deBla:Salida
fuente
La forma correcta de crear
unique_ptr:Sin embargo, su código crea 3 instancias de
Bla:blaenGetBla()función.GetBla().make_unique()crea una instancia más.NOTA:
GetBla()valor de retorno es una copia del objeto localbla.GetBla()devuelvemoveel 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::moveno mueve nada Simplemente se convierte delvaluereferencia arvaluereferencia 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 elmoveconstructor porque ha definido el destructor (y he agregado el constructor de copia en mi ejemplo)Salidas:
Vea mis comentarios a continuación:
blase construye en función aGetBla()través del constructor predeterminado.GetBla()función se construye a partir del objeto creado en# 1.blaEl objeto (construido en # 1) se destruye y se llama a su destructor.std::make_unique<Bla>llamanewy luego llama al constructor apropiado y elige elcopyconstructor.fuente