Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the usefulness of `enable_shared_from_this`?

I ran across enable_shared_from_this while reading the Boost.Asio examples and after reading the documentation I am still lost for how this should correctly be used. Can someone please give me an example and explanation of when using this class makes sense.

like image 808
fido Avatar asked Apr 03 '09 01:04

fido


People also ask

Why use enable_ shared_ from_ this?

Using enable_shared_from_this essentially allows the code to works properly in cases it would not have otherwise. By using that, it allows to find internal data used to maintain reference count.

What is boost Enable_shared_from_this?

Purpose. The header <boost/enable_shared_from_this. hpp> defines the class template enable_shared_from_this. It is used as a base class that allows a shared_ptr to the current object to be obtained from within a member function.

What is shared_ptr?

The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.

What is Make_shared in C++?

std::make_sharedAllocates and constructs an object of type T passing args to its constructor, and returns an object of type shared_ptr<T> that owns and stores a pointer to it (with a use count of 1). This function uses ::new to allocate storage for the object.


2 Answers

It enables you to get a valid shared_ptr instance to this, when all you have is this. Without it, you would have no way of getting a shared_ptr to this, unless you already had one as a member. This example from the boost documentation for enable_shared_from_this:

class Y: public enable_shared_from_this<Y> { public:      shared_ptr<Y> f()     {         return shared_from_this();     } }  int main() {     shared_ptr<Y> p(new Y);     shared_ptr<Y> q = p->f();     assert(p == q);     assert(!(p < q || q < p)); // p and q must share ownership } 

The method f() returns a valid shared_ptr, even though it had no member instance. Note that you cannot simply do this:

class Y: public enable_shared_from_this<Y> { public:      shared_ptr<Y> f()     {         return shared_ptr<Y>(this);     } } 

The shared pointer that this returned will have a different reference count from the "proper" one, and one of them will end up losing and holding a dangling reference when the object is deleted.

enable_shared_from_this has become part of C++ 11 standard. You can also get it from there as well as from boost.

like image 114
1800 INFORMATION Avatar answered Sep 23 '22 03:09

1800 INFORMATION


from Dr Dobbs article on weak pointers, I think this example is easier to understand (source: http://drdobbs.com/cpp/184402026):

...code like this won't work correctly:

int *ip = new int; shared_ptr<int> sp1(ip); shared_ptr<int> sp2(ip); 

Neither of the two shared_ptr objects knows about the other, so both will try to release the resource when they are destroyed. That usually leads to problems.

Similarly, if a member function needs a shared_ptr object that owns the object that it's being called on, it can't just create an object on the fly:

struct S {   shared_ptr<S> dangerous()   {      return shared_ptr<S>(this);   // don't do this!   } };  int main() {    shared_ptr<S> sp1(new S);    shared_ptr<S> sp2 = sp1->dangerous();    return 0; } 

This code has the same problem as the earlier example, although in a more subtle form. When it is constructed, the shared_ptr object sp1 owns the newly allocated resource. The code inside the member function S::dangerous doesn't know about that shared_ptr object, so the shared_ptr object that it returns is distinct from sp1. Copying the new shared_ptr object to sp2 doesn't help; when sp2 goes out of scope, it will release the resource, and when sp1 goes out of scope, it will release the resource again.

The way to avoid this problem is to use the class template enable_shared_from_this. The template takes one template type argument, which is the name of the class that defines the managed resource. That class must, in turn, be derived publicly from the template; like this:

struct S : enable_shared_from_this<S> {   shared_ptr<S> not_dangerous()   {     return shared_from_this();   } };  int main() {    shared_ptr<S> sp1(new S);    shared_ptr<S> sp2 = sp1->not_dangerous();    return 0; } 

When you do this, keep in mind that the object on which you call shared_from_this must be owned by a shared_ptr object. This won't work:

int main() {    S *p = new S;    shared_ptr<S> sp2 = p->not_dangerous();     // don't do this } 
like image 34
Artashes Aghajanyan Avatar answered Sep 22 '22 03:09

Artashes Aghajanyan