views:

243

answers:

4

Hello all, could someone summarize in a few succinct words how the boost shared_from_this<>() smart pointer should be used, particularly from the perspective of registering handlers in the io_service using the bind function.

EDIT: Some of the responses have asked for more context. Basically, I'm looking for "gotchas", counter-intuitive behaviour people have observed using this mechanism.

+5  A: 

From my understanding, sometimes in your code you want a class to offer up shared_ptr's to itself so that other parts of your code can obtain shared_ptr's to an object of your class after it has been constructed.

The problem is that if your class just has a shared_ptr<> to itself as a member variable, it will never get automatically destructed, since there is always "one last reference" hanging around to itself. Inheriting from enable_shared_from_this gives your class an automatic method which not only returns a shared_ptr, but only holds a weak shared pointer as a member variable so as not to affect the reference count. This way, your class will be freed as usual when the last reference to it is gone.

I've never used it, but this is my understanding of how it works.

Ken Simon
+3  A: 

shared_from_this<> is used if an object wants to get access to a shared_pointer<> pointing to itself.

Usually an object only knows about the implicit this pointer, but not about any shared_ptr<> managing it. Also, this cannot easily be converted into a shared_ptr<> that shares ownership with other existing shared_ptr<> instances, so there is no easy way for an object to get a valid shared_ptr<> to itself.

shared_from_this<> can be used to solve this problem. For example:

struct A : boost::enable_shared_from_this<A> {
   server *io;
   // ...

   void register_self() {
      io->add_client(shared_from_this());
   }
};
sth
+2  A: 

the boost::asio::io_service destructor documentation explains it fairly well

The destruction sequence described above permits programs to simplify their resource management by using shared_ptr<>. Where an object's lifetime is tied to the lifetime of a connection (or some other sequence of asynchronous operations), a shared_ptr to the object would be bound into the handlers for all asynchronous operations associated with it. This works as follows:

  • When a single connection ends, all associated asynchronous operations complete. The corresponding handler objects are destroyed, and all shared_ptr references to the objects are destroyed.
  • To shut down the whole program, the io_service function stop() is called to terminate any run() calls as soon as possible. The io_service destructor defined above destroys all handlers, causing all shared_ptr references to all connection objects to be destroyed.

Typically your objects will chain asynchronous operations where the handlers are bound to member functions using boost::bind and boost::shared_from_this(). There are some examples that use this concept.

Sam Miller
+2  A: 

The biggest "gotcha" I've run into is that it's illegal to call shared_from_this from the constructor. This follows directly from the rule that a shared_ptr to the object must exist before you can call shared_from_this.

Ben
+1 good advice, typically I make my constructor provide and provide a static `shared_ptr<Type> create` method.
Sam Miller
Ah yes!, thats it!, that's exactly the circumstances under which I was observing exceptions. Thanks. +1000 if I could :-)
Gearoid Murphy