user1009285
user1009285

Reputation: 165

Why instantiating a shared_ptr calling destructor?

Can someone explain why is the destructor of class bar being called in the line where the object of the same type is being initialized?

    #include <memory>
    #include <iostream>

    using namespace std;

    class bar
    {
      public:
        bar() {}

        ~bar() { std::cout << "destructor called " << std::endl; }
    };

    class foo
    {
      public:
        foo(std::shared_ptr<bar> barP) {}
    };


    int main() {

        std::shared_ptr<foo> f;
        std::cout << "before init " << std::endl;
        f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
        std::cout << "after init"  << std::endl;
    }

Output:

before init 
destructor called 
after init

Upvotes: 1

Views: 533

Answers (3)

Naseef Chowdhury
Naseef Chowdhury

Reputation: 2464

First of all, you should not instantiate shared_ptr in this way, use make_shared to instantiate shared_ptr. Please check the modified code -

#include <memory>
#include <iostream>

using namespace std;

class bar
{
  public:
    bar() {}

    ~bar() { std::cout << "destructor called " << std::endl; }
};

class foo
{
  public:
    foo(std::shared_ptr<bar> barP) {}
};


int main() {

    std::shared_ptr<foo> f;
    std::cout << "before init " << std::endl;
    std::shared_ptr<bar> b = std::make_shared<bar>();
    f = std::make_shared<foo>(b);
    std::cout << "after init"  << std::endl;
}

The output of the above program -

before init 
after init
destructor called 

Generally, what is happening with your code is you are passing new bar to the constructor of foo. And no one is holding the ownership of bar shared pointer. So, the ref count is becoming 0 and it is being deleted, hence the destructor is being called.

Further Read: make_shared vs new

Upvotes: 0

catnip
catnip

Reputation: 25388

This statement:

f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

constructs a temporary shared_ptr which goes out of scope at the end of the statement. At that point, the shared_ptr goes away, taking bar with it (since no copies of the shared_ptr remain alive).

But if you change foo to read like this:

class foo
{
  public:
    foo(std::shared_ptr<bar> barP) { m_bar = barP; }
    std::shared_ptr<bar> m_bar;
};

Then the output you get is probably what you were expecting, because foo maintains a copy of the shared_ptr until it (foo) goes out of scope and that copy keeps bar alive:

before init 
after init
destructor called

Live demo

Upvotes: 4

Kevin Anderson
Kevin Anderson

Reputation: 7010

It's because the bar instance only lives as long as the duration of the foo constructor. So it gets constructed, passed into the shared_ptr, which is then into the foo constructor. As soon as that constructor is done (even if on the same line) the expression itself is done, and so the shared_ptr is done, and destructs.

At the end of main right before the cout, you still have a shared_ptr to foo in f, but the unnamed shared_ptr to your bar object has already gone "out of scope".

Upvotes: 1

Related Questions