std::shared_ptr and shared_from_this

When introduced to the std::shared_ptr, many people immediately want to produce a function that returns a std::shared_ptr to this.

//BAD! creates multiple control blocks to the same pointer
std::shared_ptr<Thingy> get_a_thingy() {
    return this;
}

When the function above is used to generate a std::shared_ptr, each call will create a new control block. The first std::shared_ptr to go out of scope will destruct the object, leaving the other std::shared_ptr objects pointing to the deleted memory.

The C++ standard gets around this issue via the function shared_from_this, which safely creates shared pointers to this without duplicate control blocks.

In order to enable the shared_from_this function, your class must inherit from std::enable_shared_from_this<T>:

class Thingy : public std::enable_shared_from_this<Thingy> {...}

Using the shared_from_this function, the correct example for returning a std::shared_ptr to our object would be:

//Requires a shared_ptr to be created before use
std::shared_ptr<Thingy> get_a_thingy() {
     return shared_from_this();
}

One caveat to the shared_from_this function: a std::shared_ptr object must be created before shared_from_this is used. The shared_from_this function searches for the existing control block rather than creating a new one.

The simplest way to control this is to make the constructor private. Objects will be created using a static factory function that passes arguments to the private constructor.

// factory function that perfect-forwards args
// to a private ctor
template<typename ... T>
static std::shared_ptr<Thingy> create(T&& ... t) {
    return std::shared_ptr<Thingy>(new Thingy(std::forward<T>(t)...));
}

Using std::forward in the factory allows you to have multiple constructor prototypes while using a single create function:

private:
     //We make constructor private - shared_from_this() breaks if a shared
     //ptr has never been created before.  (It looks for the control block)
     Thingy() : name_("Nameless Thing") {}
     Thingy(std::string name) : name_(name) {}

So now that we've set up our class to enable shared_from_this, how do we actually put everything together?

When creating the object, simply use the static factory function we defined:

auto thingy = Thingy::create("Thing 1");

Once the object is created, you can safely generate a std::shared_ptr:

auto t = thingy->get_a_thingy();

And that's all there is to it!

Example Source Code

Further Reading