2

I read about std::enable_shared_from_this and I understand how it works, but I don't understand what problem it designed to solve?

For example from here: What is the usefulness of `enable_shared_from_this`?

class Y: public std::enable_shared_from_this<Y>
{
public:

    std::shared_ptr<Y> f()
    {
        return shared_from_this();
    }
};

std::shared_ptr<Y> p(new Y);
std::shared_ptr<Y> q = p->f();

yeah, great we can write q=p->f();, but why not just q = p;?

In general case we have shared_ptr, but for some reason it is not available somewhere, so we have to restore it from this, but if we pass raw pointer from shared_ptr to somewhere then we have problem, because of all shared_ptr safety go away if we take pointer from std::shared_ptr::get, and pass raw pointer to someone.

Community
  • 1
  • 1
user1244932
  • 7,352
  • 5
  • 46
  • 103

3 Answers3

3

You have a method in your class that needs to hand out weak or shared pointers to this. Not just return, but maybe call a different function, passing a shared_ptr pointing to itself to it.

You either have to augment the method with a shared-ptr-to-this, change it to a non-method taking a shared ptr, store a weak ptr to this in the class, or inherit from enable_shared_from_this.

enable_shared_from_this is basically "store a weak_ptr to yourself", with some help from the shared-ptr creating code to initialize it.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • 1
    `You have a method in your class that needs to hand out weak or shared pointers to this` but why I need in real life such strange method? – user1244932 Nov 20 '15 at 01:55
  • 1
    @user1244932 Self register with a handler somewhere? Pass out a shared pointer to a variable stored in itself using the aliasing shared pointer constructor? Any reason you'd want to create a shared ptr copy, but instead of in some code outside of the class, inside a method. – Yakk - Adam Nevraumont Nov 20 '15 at 02:12
  • But in such cases, isn't right solution to leave this stuff to owner of `shared_ptr`? It looks like hacks, when re factoring will take too much efforts, and you use such solution, but in that case why c++ standard committee take care about such situation? – user1244932 Nov 20 '15 at 02:23
  • @user1244932 If something is a `shared_ptr` is has no one owner. `shared_ptr` means shared ownership. You can restrict the multiple owners externally, but if you have one owner always, you shouldn't *be* a `shared_ptr`. You might not like shared ownership, but that just is a reason not to use shared_ptr, not a reason for shared_ptr to not support it. – Yakk - Adam Nevraumont Nov 20 '15 at 02:42
2

Y::f() may want to call another function which takes shared_ptr<Y> or shared_ptr to some other type which happens to be a sub-object or member of Y.

  • But why I have mixed `Y` and its storage model? I mean there are `Y` and its implementation, and there are methods how can I manage their life time `std::shared_ptr`, `std::unique_ptr` etc, why I have to mix these orthogonal things – user1244932 Nov 20 '15 at 02:03
  • You're right, it's not nice in general. You should avoid doing that if possible. But if this becomes too hard, `enable_shared_from_this` helps you. – Constantin Baranov Nov 20 '15 at 02:07
2

I think it I found a more satisfactory real-life example.

In Boos.Asio you can program asynchronously. When you call an async function, it returns immediately. Though you want to keep certain resources alive but these go out of scope. How can you achieve asynchronous programming in a nice way?

Well, a pattern is thinking of a pipeline, where, for example, you want to listen to connections and later perform some operation. Look at the class tcp_connection here: https://www.boost.org/doc/libs/1_69_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html

So, what does this server do? It creates a tcp connection that waits for a request and returns the daytime.

As you can see the connection holds the socket and a string (resources to be kept alive). So async_read and async_write will be called on it. In order to keep the tcp_connection instance alive, shared_from_this() is passed to each handler in the pipeline, binding lifetime of tcp_connection to that of the handlers: the state will be kept alive exactly for as long as needed. If there is another phase in the pipeline it is a matter of forwarding the reference count to the next pipeline phase. keeping the tcp_connection alive this way makes sure it will not last longer or shorter than it should: it will last exactly what it needs to assist the request and return.

Germán Diago
  • 7,473
  • 1
  • 36
  • 59