Using boost::enable_shared_from_this

The boost::enable_shared_from_this class is designed to allow a method of an object that has already been instantiated wrapped in a shared_ptr to return this as a shared_ptr correctly. This is necessary because simply returning a shared_ptr(this) will create another shared_ptr with its own reference count, which would conflict with the exisiting one and subvert reference counting.

For example, consider the class outline below which is fairly typical of a heap-allocated, non-copyable class using shared_ptr:

#include <boost/shared_ptr.hpp>
#include <boost/core/noncopyable.hpp>

class X : private boost::noncopyable
{
public:
    typedef boost::shared_ptr<X> Ptr;
    typedef boost::shared_ptr<const X> ConstPtr;
private:
    X()
    {
    }
public:
    static Ptr New()
    {
        return Ptr(new X());
    }
};

Now imagine we add the following method, which returns this wrapped in a shared_ptr, perhaps to facilitate method chaining:

    Ptr F()
    {
        // Do something...
        return Ptr(this);
    }

The problem now is that the Ptr returned by F() is in addition to the Ptr already wrapping this instance, so although it refers to the same underlying raw pointer, it has its own reference count, as the following program demonstrates:

int main()
{
    X::Ptr x1 = X::New();
    X::Ptr x2 = x1->F();
    std::cout << std::boolalpha << "x1 == x2?: "<< (x1 == x2) << "\n";
    std::cout << std::boolalpha << "!(x1 < x2 || x < x2)?: " <<  (!(x1 < x2 || x2 < x1)) << "\n";
}

This outputs:

x1 == x2?: true
!(x1 < x2 || x < x2)?: false

Operator== is showing that the two variables are holding the same raw pointer, but operator<, which is overloaded to show whether two pointers actually share ownership, shows that they do not.

When the first pointer goes out of scope, it will decrement its reference count to 0 and delete the object. When the second one too goes out of scope, it will attempt to do the same, with undefined results.

The solution is to use boost::enable_shared_from_this. This just involves:

  1. Include boost/enable_shared_from_this.hpp
  2. Derive your class publicly from boost_enable_shared_from_this, which takes the class as a template parameter (the Curiously Recurring Template Pattern)
  3. Whenever you want to return this wrapped in a shared_ptr, use the inherited shared_from_this() method.

Here is our example class with those changes added:

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/core/noncopyable.hpp>

class X : public boost::enable_shared_from_this<X>,
   private boost::noncopyable
{
public:
    typedef boost::shared_ptr<X> Ptr;
    typedef boost::shared_ptr<const X> ConstPtr;
private:
    X()
    {
    }
public:
    static Ptr New()
    {
        return Ptr(new X());
    }
    Ptr F()
    {
        return shared_from_this();
    }
};

This is the result of running the test program now:

x1 == x2?: true
!(x1 < x2 || x < x2)?: true

So now the ownership of the raw pointer is correctly shared.

References:
noncopyable
shared_ptr class template
enable_shared_from_this