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 from GetBla()
  • The return value from GetBla() after it was used in std::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:

  1. Local object bla in GetBla() function.
  2. Return value of GetBla().
  3. Finally, make_unique() creates one more instance.

NOTE:

  1. In presence of user-defined destructor, the compiler does not generate move-constructor, so GetBla() return value is a copy of the local object bla.
  2. Since GetBla() returns move'ed local object, copy-elision is suppressed.

Tags:

C++

Unique Ptr