What Is the Usefulness of 'Enable_Shared_From_This'

What is the usefulness of `enable_shared_from_this`?

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.

When should we use std::enable_shared_from_this

The hint about when std::enable_shared_from_this<T> is useful is in its name: when yielding objects based on some requests it may be necessary to return a pointer to an object itself. If the result should be a std::shared_ptr<T> it becomes necessary to return such a pointer from within a member function where there is generally no std::shared_ptr<T> accessible.

Having derived from std::enable_shared_from_this<T> provides a way to get hold of a std::shared_ptr<T> given just a pointer of type T. Doing so does, however, assume that the object is already managed via a std::shared_ptr<T> and it would create mayhem if the object is allocated on the stack:

struct S: std::enable_shared_from_this<S> {
std::shared_ptr<S> get_object() {
return this->shared_from_this();
};
}

int main() {
std::shared_ptr<S> ptr1 = std::make_shared<S>();
std::shared_ptr<S> ptr2 = ptr1->get_object();
// ...
}

In a realistic scenario there is probably some condition under which a std::shared_ptr<T> to the current object is returned.

When is enable_shared_from_thisS useful?

The core problem is here, that not every shared pointer around in your code base is "known" to the rest of the code for some reason.

If you have access to a already given shared_ptr you should always use shared_ptr<S> sp2 = sp1; as you wrote. The is absolutely fine and better as using std::enable_shared_from_this.

Lets take the following example:

struct S: std::enable_shared_from_this<S>
{
std::shared_ptr<S> getPtr() { return shared_from_this(); }
};

// Here we have no interface for providing a shared_ptr, maybe
// code that we can't change or maintain or comes as callback from
// a library we want to use
void f( S* s )
{
// here we have no access to shared_ptr<S>...
// so we need to have access to the unique counting instance
// of all other shared_ptr which are pointing to this object
std::shared_ptr<S> p3 = s->getPtr();
std::cout << p3.use_count() << std::endl;

// do some stuff....

}

int main()
{
std::shared_ptr<S> p1 = std::make_shared<S>();
std::cout << p1.use_count() << std::endl;

// This example is useless, as you can directly use p1
std::shared_ptr<S> p2 = p1->getPtr();
std::cout << p1.use_count() << std::endl;
std::cout << p2.use_count() << std::endl;

// But if we have to use a interface, which is not providing access via shared_ptr like this:
f(p1.get());
}

The key problem which is solved here is simply to get access to the common "handle" which is connecting all the other shared_ptr around in our system IF! we don't have access to any of the shared_ptr at all!

The reasons why we can't access any of the existing shared_ptr to our object can be many like: Use of old interfaces which only allow raw pointers but we want to use shared ptr in the rest of our code, using call backs from libraries which also only support raw pointers and so on.

Using std::enable_shared_from_this<S> has some drawbacks:

Your interfaces can not use const S* anymore, as creating a new shared_ptr will modify the data of std::enable_shared_from_this which is now a base class of your class or struct. Also it increases the size of your object.

Why we need enabled_shared_from_this

shared_from_this is a very special animal. Usually, you should separate responsibilities: A class does one thing, and one thing only. Owning a resource is such a responsibility, so a class should either own a resource and do nothing else, or do something else but not own a resource.

The use for shared_from_this is when this principle is violated, and a class knows that it is owned by a shared pointer. In that case, you need a way to get at that ambient shared pointer that is owning you. You cannot simply say shared_ptr<T>(this), because that would create a new owner, rather than share ownership with the existing owner.

To communicate from the class to its ambient owner, you need to derive from enable_shared_from_this, and then use shared_from_this to produce a new shareholder.

(This works practically by adding a weak_ptr<T> member to the class, and upon creation of the ambient shared pointer, that weak pointer is set to observe the shared pointer. So shared_from_this is a simple lock() invocation on the weak pointer.)


Here's an example to clarify the usage:

auto x = std::make_shared<T>();
f(*x);

// ...

void f(T const & t)
{
auto y = t.shared_from_this();
// ...
}

Inside f, we don't see the owner of t immediately, but shared_from_this brings it out.

How useful is std::enable_shared_from_this if you already have a std::shared_ptr at your disposal?

Two use cases immediately spring to mind:

  1. It allows the object to hand itself off to something else that then keeps a shared pointer. The object itself doesn't own a shared copy. The point of shared_from_this is to give the object an internal weak_ptr.

  2. Since passing shared pointers around is expensive (and redundant, when you know it's always owned within a call stack), it is standard practice to pass around the contained object as a reference. If, somewhere down the call stack, you need to obtain the shared pointer again, you can do so via shared_from_this.

What is the purpose of inheriting from enable_shared_from_this?

Cppreference has a good example on why.

If you want to return a std::shared_ptr of this while *this is already owned by a std::shared_ptr and you don't return shared_from_this() but return a new std::shared_ptr<T>(this) instead then you will end up with 2 shared pointers that don't know they're both owning the same object and thus the use_count() will be wrong which will cause a double delete, which is undefined behavior.

c++ tr1 enable_shared_from_this what's the advantage?

enable_shared_from_this is most useful in class implementation whose objects will be shared. You want to share the same reference counter for all instances of shared_ptrs of your object (is usually done by copying shared_ptr), but class implementation doesn't have any to make a copy. In this case you can use shared_from_this.

Consider:

struct A;

void f(shared_ptr<A> const&) {...}

struct A: public enable_shared_from_this<A>
{
void a_f()
{
// you need to call f() here passing itself as a parameter
f(shared_from_this());
}
};

shared_ptr<A> a_ptr(new A());
a_ptr->a_f(); // in inner call to f() will be used temporary shared_ptr<A>
// that uses (shares) the same reference counter as a_ptr

Why do we use enable_shared_from_this template?

Whats wrong with shared_ptr p(new Y);?

There is nothing wrong with it, only issue you may not have it inside a member of class Y and sometimes you want a member to return std::shared_ptr to itself. std::shared_ptr<Y>( this ) is an obviously wrong way to create one.

I wonder if such example can make things clearer and would be still simple enough:

std::shared_ptr<Y> Y::getObject() 
{
return some_condition ? shared_from_this() : std::make_shared<Y>( somedata );
}


Related Topics



Leave a reply



Submit