What is the need for enable_shared_from_this? [duplicate]

試著忘記壹切 提交于 2019-12-05 00:18:13


I am new to C++11 and I came across enable_shared_from_this. I do not understand what it is trying to achieve? So I have a program that uses enable_shared_from_this.

struct TestCase: enable_shared_from_this<TestCase>
std::shared_ptr<testcase> getptr() {
    return shared_from_this();

~TestCase() { std::cout << "TestCase::~TestCase()"; }

int main()
std::shared_ptr<testcase> obj1(new TestCase);
std::shared_ptr<testcase> obj2 = obj1->getptr();
// The above can be re written as below
//  std::shared_ptr<testcase> obj2 = shared_ptr<testcase>(obj1);

My question is when I need a pointer to 'this', why not use the obj itself. Why to return a 'this' from a function of that class like using getptr() and then returning shared_from_this()???? I do not understand.

Second question, if enable_shared_from_this is NOT used, why is the dtor called twice that creates a problem, a crash!!!!

Another way I can bypass using enable_shared_from_this is like this. Add this in class TestCase

  std::shared_ptr getptr1(shared_ptr obj) {
   return std::shared_ptr(obj);

and from main make a call this this:

  std::shared_ptr bp2 = bp1->getptr1(bp1);

And done. We do not need enable_shared_from_this. Why on the earth do we need it??


A shared_ptr manages two different things. It has a pointer to its data, and a pointer to a reference counting block.

The reference counting block has a strong counter, a weak counter and a destroy operation in it.

When you std::shared_ptr<X>(pX), it creates a new reference counting block that, when the last (strong) reference goes away, it deletes the pX object.

The same thing happens when you std::shared_ptr<X>(this).

So, if you wrap an object in std::shared_ptr in two different spots, you have to different reference counting blocks, and they both want to destroy the object when they go away.

enable_shared_from_this<X> changes how this works. When you create a shared pointer to an object inheriting from it, it stores a std::weak_ptr<X> inside the enable_shared_from_this<X>. A weak pointer stores a pointer to the above reference counting block, but only "holds" a weak reference (not a strong one).

Then, when you call shared_from_this(), it does a .lock() on that weak pointer and returns a shared pointer using the reference counting block of the old one created (as stored by the weak_ptr).

Now, the above is an example implementation of what it could do: the standard mandates behavior, not implementation, and the weak_ptr is a possible way to implement it. Similarly, the reference counting block detail is just an example implementation.

The core issue is that two independent shared pointers wrapping the same pointer will try to independently manage the pointer's lifetime. enable_shared_from_this makes the first smart pointer's reference counting block be used by later shared_from_this() return values.


Short answer: you need enable_shared_from_this when you need to use inside the object itself existing shared pointer guarding this object.

Out of the object you can simply assign and copy a shared_ptr because you deal with the shared_ptr variable as is. But when you are in one of the class members then if you need to use a shared pointer pointing to self object (instead of ordinary this) and there is no such shared pointer in arguments of that method then shared_from_this() is what will help you. Using std::make_shared(this) is absolutely unsafe as you can not have two shared pointers on the same object. While, shared_from_this() is safe because it uses weak_ptr to "resolve" already existing shared_ptr.

To be able to use shared_from_this() you must first use enable_shared_from_this in your class definition which adds a shared_from_this() method to your class.

Note, shared_from_this() can not be used in the class constructor! At that time the shared_ptr does not exist yet, so the shared_from_this() can't resolve any exisiting pointers.

And when and why one can need a shared pointer to this instead of just this it is quite other question. For example, it is widely used in asynchronous programming for callbacks binding.