std::weak_ptr: Breaking Cycles of Counted Rerences

A std::weak_ptr is basically a std::shared_ptr that doesn't increase the reference count. It is defined as a smart pointer that holds a non-owning reference, or a weak reference, to an object that is managed by another std::shared_ptr.

This smart pointer is useful to solve some annoying problems that you can't fix with raw pointers. We will see how shortly.

How to construct a std::weak_ptr

You can only create a std::weak_ptr out of a std::shared_ptr or another std::weak_ptr. For example:

std::shared_ptr<int> p_shared = std::make_shared<int>(100);
std::weak_ptr<int>   p_weak1(p_shared);
std::weak_ptr<int>   p_weak2(p_weak1);

In the example above p_weak1 and p_weak2 point to the same dynamic data owned by p_shared, but the reference counter doesn't grow.

std::weak_ptr in action

A std::weak_ptr is a sort of inspector on the std::shared_ptr it depends on. You have to convert it to a std::shared_ptr first with the lock() method if you really want to work with the actual object:

std::shared_ptr<int> p_shared = std::make_shared<int>(100);
std::weak_ptr<int>   p_weak(p_shared);
// ...
std::shared_ptr<int> p_shared_orig = p_weak.lock();
//

Of course p_shared_orig might be null in case p_shared got deleted somewhere else.

std::weak_ptr is a problem solver

A std::weak_ptr makes the problem of dangling pointers, pointers that point to already deleted data, super easy to solve. It provides the expired() method which checks whether the referenced object was already deleted. If expired() == true, the original object has been deleted somewhere and you can act accordingly. This is something you can't do with raw pointers.

As I said before, a std::weak_ptr is also used to break a circular reference. Let's go back to the Player example above and change the member variable from std::shared_ptr<Player> companion to std::weak_ptr<Player> companion. In this case we used a std::weak_ptr to dissolve the entangled ownership. The actual dynamically-allocated data stays in the main body, while each Player has now a weak reference to it. Run the code with the change and you will see how the destructor gets called twice, correctly.