Unique pointer - Why is the destructor called 3 times
There are indeed 3 times that an instance of Bla
is constructed.
Bla GetBla() {
Bla bla; // 1st construction
return std::move(bla); // 2nd construction (return by copy)
}
Don't return by move. Just return bla
, in most cases the copy will be elided.
auto bla = std::make_unique<Bla>(GetBla()); // 3rd construction - Bla copy construction
Note that make_unique<Bla>
always constructs a new instance. In this case because you're passing another instance, it becomes copy-construction.
A hint that copy construction takes place is that your default constructor is invoked only once, while the destructor is invoked 3 times. That's because in the other 2 cases the implicit copy (or move) constructor is invoked (Bla::Bla(Bla const&)
).
The compiler may even warn you that
moving a local object in a return statement prevents copy elision.
I'm not 100% sure, but I think you get the three desctructor calls from:
- The local variable
bla
fromGetBla()
- The return value from
GetBla()
after it was used instd::make_unique<Bla>(GetBla());
- Obviously from the destructor of the
std::unique_ptr
The easiest way is to let std::make_uniqe
invoke the default constructor of Bla
:
auto bla = std::make_unique<Bla>(); // Calls Bla::Bla() to initalize the owned object
#include <iostream>
#include <memory>
class Bla {
public:
Bla() { std::cout << "Constructor!\n"; }
~Bla() { std::cout << "Destructor!\n"; }
};
int main() {
auto bla = std::make_unique<Bla>();
}
Output
Constructor!
Destructor!
The right way to create unique_ptr
:
auto bla = std::make_unique<Bla>();
However, your code creates 3 instances of Bla
:
- Local object
bla
inGetBla()
function. - Return value of
GetBla()
. - Finally,
make_unique()
creates one more instance.
NOTE:
- In presence of user-defined destructor, the compiler does not generate move-constructor, so
GetBla()
return value is a copy of the local objectbla
. - Since
GetBla()
returnsmove
'ed local object, copy-elision is suppressed.