Mateusz Krzaczek
Mateusz Krzaczek

Reputation: 614

shared_ptr.reset() not deleting

Im starting learning about shared_ptr and weak_ptr. In theory everything looks simple. But when I started to testing, well... I have this really simple program:

#include <iostream>
#include <memory>
using namespace std;

class Second
{
public:
    Second()
    {
        cout << "Second created" << endl;
    }
    ~Second()
    {
        cout << "Second deleted" << endl;
    }
};

class Main
{
public:
    shared_ptr<Second> second;
    Main()
    {
        cout << "Main created" << endl;
        second = make_shared<Second>(*(new Second()));
    }
    ~Main()
    {
        second.reset();
        cout << "Main deleted" << endl;
    }
};

void fun()
{
    shared_ptr<Main> main = make_shared<Main>(*(new Main()));
}

int main()
{
    cout << "Program started" << endl;
    fun();

    cout << "Program ended" << endl;
    return 0;
}

The problem is, that Second is never deleted. Here is my output:

Program started
Main created
Second created
Main deleted
Program ended

Whats going on? I thought, that if I reset shared_ptr, and its last shared_ptr existing, object is deleting automatically.

Upvotes: 1

Views: 3776

Answers (2)

Matthieu M.
Matthieu M.

Reputation: 300409

As I said, the situation is quite complicated, so I'll need a schema.

class Main {
public:
    shared_ptr<Second> second;
    Main()
    {
        cout << "Main created" << endl;
        second = make_shared<Second>(*(new Second()));
    }
    ~Main()
    {
        second.reset();
        cout << "Main deleted" << endl;
    }
};

void fun()
{
    shared_ptr<Main> main = make_shared<Main>(*(new Main()));
}

Right after the creation of main, we have:

 <anon: Second> (leaked)

 <anon: Main>   (leaked)
             \
             |---> <Main.second: Second>
             /
 <main: Main>

Note that main.second is copied from <anon>.second so, as those are shared_ptr<Second> they both point to the same instance of Second.

Then, main dies, we are left with:

<anon: Second> (leaked)

<anon: Main> (leaked) ---> <Main.second: Second> (indirectly leaked)

Note that second.reset() does not necessarily destroy the pointed-to object. It simply reset the local instance of shared_ptr. If this was the last instance pointing to the object, then the object is destroyed, but otherwise... nothing.

Upvotes: 2

SoapBox
SoapBox

Reputation: 20609

You're initializing your shared pointers wrong. You don't need to use new at all when using make_shared. The parameters you pass to make_shared are forwarded to the constructor of the class you're making.

So in your code, your make_shared calls should look like this:

shared_ptr<Main> main = make_shared<Main>();

and

shared_ptr<Second> main = make_shared<Second>();

Instead, what you've done is leaked a version of each class (by using new explicitly and not deleting it) and then copied the leaked value into a second version. By splitting up the expression into multiple lines, we can more easily see what you've done wrong:

Second *p = new Second;
shared_ptr<Second> ss = make_shared<Second>(*p); // Calls the Second class copy constructor
// p is never deleted, so it is leaked.

Upvotes: 8

Related Questions