Remarks on enable_shared_from_this
std::enable_shared_from_this
is a template base class that allows
derived classes to get a std::shared_ptr
to themselves. This can be
handy, and it's not something that C++ classes can normally do. Calling
std::shared_ptr<T>(this)
is not an option as it creates a new shared pointer
independent of the existing one, which leads to double destruction.
The caveat is that before calling the shared_from_this()
member function, a
shared_ptr
to the object must already exist, otherwise undefined behavior results.
In other words, the object must already be managed by a shared pointer.
This presents an interesting issue. When using this technique, there are member
functions (those that rely on shared_from_this()
) that can only be called if
the object is managed via a shared_ptr
. This is a rather subtle requirement:
the compiler won't enforce it. If violated, the object may even work at runtime
until a problematic code path is executed, which may happen rarely – a nice
little trap. At the very least, this should be prominently mentioned in the
class documentation. But frankly, relying on the documentation to
communicate such a subtle issue sounds wrong.
The correct solution is to let the compiler enforce it. Make the
constructors private and provide a static factory method that returns a
shared_ptr
to a new instance. Take care to delete the copy constructor
and the assignment operator to prevent anyone from obtaining
non-shared-pointer-managed instances this way.
Another point worth mentioning about enable_shared_from_this
is that the
member functions it provides, shared_from_this()
and weak_from_this()
, are
public. Not only the object itself can retrieve it's owning shared_ptr
,
everyone else can too. Whether this is desirable is essentially an API design
question and depends on the context. To restrict access to these functions,
use private inheritance.
Overall, enable_shared_from_this
is an interesting tool, if a bit
situational. However, it requires care to use safely, in a way that prevents
derived classes from being used incorrectly.
Comments