ssk
ssk

Reputation: 9265

Accessing weak_ptr after deleting the original pointer

I get a runtime error when I execute the below code:

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

class Test
{
public:
    int value;
    Test( )
    {
        value = 1;
    }

    ~Test( )
    {

    }
};

int main() {
    shared_ptr<Test> pTest =  shared_ptr<Test>( new Test( ) );
    std::vector<weak_ptr<Test>> testList;

    testList.push_back( weak_ptr<Test>(pTest) );
    cout << "\n Before Deletion";
    for (unsigned int i=0; i < testList.size(); i++)
    {
        try
        {
            auto p = testList[i].lock();
            cout << "\n Item not null: " << p->value;
        }
        catch (bad_weak_ptr b)
        {
            wcout << L"Null object" << endl;
        }
    }

    pTest.reset( );

    cout << "\n After Deletion";
    for (unsigned int i=0; i < testList.size(); i++)
    {
        try
        {
            auto p = testList[i].lock();
            cout << "\n Item not null: " << p->value;
        }
        catch (bad_weak_ptr b)
        {
            wcout << L"Null object" << endl;
        }
    }

    // your code goes here
    return 0;
}

I was trying to find whether the pointer is still accessible (shouldn't be) after deleting the original shared pointer.

Upvotes: 3

Views: 1738

Answers (2)

IdeaHat
IdeaHat

Reputation: 7881

Lock doesn't check for null, it promotes a weak_ptr to a shared pointer. It doesn't throw when the object is deleted, but rather returns null.

This is what you should be doing.

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

class Test
{
public:
    int value;
    Test( )
    {
        value = 1;
    }

    ~Test( )
    {

    }
};

int main() {
    shared_ptr<Test> pTest =  shared_ptr<Test>( new Test( ) );
    std::vector<weak_ptr<Test>> testList;

    testList.push_back( weak_ptr<Test>(pTest) );
    cout << "\n Before Deletion";
    for (unsigned int i=0; i < testList.size(); i++)
    {
      auto p = testList[i].lock();
        if (p)
        {

            cout << "\n Item not null: " << p->value;
        }
        else
        {
            wcout << L"Null object" << endl;
        }
    }

    pTest.reset( );

    cout << "\n After Deletion";
    for (unsigned int i=0; i < testList.size(); i++)
    {
      auto p = testList[i].lock();
        if (p)
        {

            cout << "\n Item not null: " << p->value;
        }
        else
        {
            wcout << L"Null object" << endl;
        }
    }

    // your code goes here
    return 0;
}

To clarify, what happens when you to test_list>lock after pTest is reset is you get a shared_ptr which contains NULL. and ((Test*)NULL)->value is what happen when you do p->value, which is an obvious segfault.

The whole point of having a weak_ptr is to allow users the ability to safely get a reference to an object that may go out of scope. Exceptions would be a poor mechanism for this because exceptions are SLOW, and it is not necessarily a fatal error if the weak_ptr's parent goes out of scope. So the mechanism is lock either returns a new counted reference when promoted, or NULL if it can no longer promote the ownership level (the parent has expired).

Upvotes: 2

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145419

You could read the documentation instead of making assumptions about how things work.

lock does not signal nullpointer by throwing an exception: it returns a nullpointer.

So,

        auto p = testList[i].lock();
        if( p != nullptr )
        {
            cout << "\n Item not null: " << p->value;
        }
        else
        {
            cout << "\n Item is null." << endl;
        }

Upvotes: 1

Related Questions