In this post I want to demonstrate how C++11 smart pointers can be abused to track the lifetime of an object without taking ownership of them. Due to the resemblance to std::enable_shared_from_this I call this technique enable_weak_from_this. One word of warning though, this technique is a crude hack and can lead to dangling pointers and undefined behavior. You should NOT use it in production code.

Intent

Allow an object t whose lifetime is managed by another object (which is not a smart pointer) to create smart references to itself that know whether t still exists or if it has been deleted.

Implementation

The core of enable_weak_from_this is a std::shared_ptr private member variable that is constructed with the this pointer and a custom deleter that does not delete the "managed" pointer on desctruction. At first, this might seem pointless since the job of shared_ptr is to delete pointers when there are no other shared_ptr that reference them. But what remains is the reference counting mechanism which can be used to track the lifetime of t. The shared_ptr member of t guarantees that during its lifetime the reference count is always equal or greater than one. After t is deleted the reference count drops to zero. So the reference counter of the private shared_ptr member "tracks" the lifetime of t.

To create smart references from t to itself, there is a public method that returns a std::weak_ptr which is constructed from the shared_ptr member. These non-owning weak references now allow to access t (via a prior conversion to a shared_ptr) during its lifetime.

Here is the complete definition of enable_weak_from_this:

Sample Code

And here is a small example that uses enable_weak_from_this, which I'll explain below:

A inherits from enable_weak_from_this<A> and therefore objects of type A are able to create those smart references to themselves. A also has a method to create a "child" object of type B which is constructed with a weak reference to its creator. All the usage of the weak reference is in B::callHello where weak_ptr::lock() is used to create a temporary shared_ptr<A> of the creator object if it still exists. If the creator has been deleted, lock() will return an empty shared_ptr. Finally main demonstrates what happens on b->callHello() calls before and after the creator of b is deleted.

Problems

It is possible to create a shared_ptr of t whose lifetime exceeds the lifetime of t by storing the return value of weak_ptr::lock(). So care must be taken that t is not deleted while using the acquired shared_ptr.