c++shared-ptrsmart-pointersweak-ptrrefcounting

Weak pointer library implementation C++


#include <iostream>
using namespace std;

class Printer
{
    weak_ptr<int> m_Value{};
public:
    void SetValue(weak_ptr<int> p)
    {
        m_Value = p;
    }

    void Print() const
    {
        cout << "ref count = " << m_Value.use_count() << endl;
        if (m_Value.expired())
        {
            cout << "resource expired";
            return;
        }
        auto sp = m_Value.lock();
        cout << "sp ref count = " << sp.use_count() << endl;

        cout << "Value is = " << *sp << endl;
    }
};

int main()
{
    Printer prn;
    int num;
    cout << "Enter num = ";
    cin >> num;
    shared_ptr<int> p{new int(num)};
    prn.SetValue(p);
    if (*p > 10)
    {
        p = nullptr;
    }
    prn.Print();
}

I was learning C++ 11/14/17 concepts and I learned about this weak pointer concept. Above code is the example I learned and implemented and understood it and above code has no bug. But my doubt is on library design for this weak pointer.

auto sp = m_Value.lock();

why this line is left for programmer to call instead of putting inside weak pointer design itself, because whenever the shared pointer shares value to weak pointer ref count has to be incremented automatically right? what's the corner case that doesn't require this line to be called and so ref count shouldn't be increased.


Solution

  • What you're describing, with automatic incrementing and decrementing of the reference count would turn what was supposed to be a weak pointer into a shared pointer.

    A shared pointer will automatically increment the reference count every time we copy or assign the shared pointer (and decrement it again when a shared pointer is destroyed).

    But a weak pointer is intended to deal with things like cycles in a structure:

    enter image description here

    If we use a shared pointer here, each node has a reference to it, so none of the nodes will ever be deleted, even if (for example) we have no other pointer to any of these nodes, so they're all actually inaccessible. So, the memory to all of them will leak.

    A weak pointer fixes this problem:

    enter image description here

    The "backward" pointer represented by the dotted line here is a weak pointer. There mere fact that it exists does not increment the reference count to A. So, if we have no other pointer into these nodes, their reference counts will all drop to 0, and they'll all be deleted.

    But, if/when we decide we need to look at whatever it is that C points to, we convert that weak pointer to a shared pointer. That increments the reference count to A. Then when we're done using that link, we dispose of the shared pointer, decrementing the reference count for A.

    But the whole idea here is that the pointer from C to A will only assure that A remains accessible when we're actually using that link. If all the other references to A are destroyed, and we're not currently using the link from C to A, then all the nodes (A, B and C) should be destroyed.

    To get that behavior, we need to do something that explicitly specifies when we're using that link back from C to A.