I frequently see this pattern in code, binding shared_from_this as the first parameter to a member function and dispatching the result using an async_* function. Here’s an example from another question:
void Connection::Receive()
{
boost::asio::async_read(socket_,boost::asio::buffer(this->read_buffer_),
boost::bind(&Connection::handle_Receive,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
The only reason to use shared_from_this() instead of this is to keep the object alive until the member function gets called. But unless there’s some kind of boost magic somewhere, since the this pointer is of type Connection*, that’s all handle_Receive can take, and the smart pointer returned should be converted to a regular pointer immediately. If that happens, there’s nothing to keep the object alive. And, of course, there’s no pointer in calling shared_from_this.
However, I’ve seen this pattern so often, I can’t believe it’s as completely broken as it seems to me. Is there some Boost magic that causes the shared_ptr to be converted to a regular pointer later, when the operation completes? If so, is this documented somewhere?
In particular, is it documented somewhere that the shared pointer will remain in existence until the operation completes? Calling get_pointer on the strong pointer and then calling the member function on the returned pointer is not sufficient unless the strong pointer isn’t destroyed until the member function returns.
In short,
boost::bindcreates a copy of theboost::shared_ptr<Connection>that is returned fromshared_from_this(), andboost::asiomay create a copy of the handler. The copy of the handler will remain alive until one of the following occurs:run(),run_one(),poll()orpoll_one()member function has been invoked.io_serviceis destroyed.io_service::servicethat owns the handler is shutdown viashutdown_service().Here are the relevant excerpts from the documentation:
boost::bind documentation:
boost::asio
io_service::post:boost::asio
io_service::~io_service:While dated (2007), the Networking Library Proposal for TR2 (Revision 1) was derived from Boost.Asio. Section
5.3.2.7. Requirements on asynchronous operationsprovides some details for the arguments toasync_functions:Thus:
shared_ptr<Connection>, increasing the reference count of theConnectioninstance while the copies of handler remain alive.io_serive::serviceis shutdown or theio_serviceis destroyed. In the example, the copies of handler will be destroyed, decreasing the reference count ofConnection, and potentially causing theConnectioninstance to be destroyed.Connection, and potentially causing it to be destroyed.asnyc_‘s arguments, will be executed sequentially, and not concurrent. This includesio_handler_deallocateandio_handler_invoke. This guarantees that the handler will not be deallocated while the handler is being invoked. In most areas of theboost::asioimplementation, the handler is copied or moved to stack variables, allowing the destruction to occur once execution exits the block in which it was declared. In the example, this ensures that the reference count forConnectionwill be at least one during the invocation of the handler.