Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the need for enable_shared_from_this? [duplicate]

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??

like image 627
Bhathura Avatar asked Mar 16 '16 16:03

Bhathura


1 Answers

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.

like image 116
Yakk - Adam Nevraumont Avatar answered Nov 15 '22 05:11

Yakk - Adam Nevraumont