我还看到这种模式被大量使用并且(感谢@Tanner)我可以看到为什么在多线程io_service
中运行时使用它。但是,我认为它仍然存在生命周期问题,因为它用潜在的内存/资源泄漏代替了潜在的崩溃......
感谢 boost::bind,绑定到 shared_ptrs 的任何回调都成为对象的“用户”(增加对象 use_count),因此在调用所有未完成的回调之前不会删除该对象。
每当在相关计时器或套接字上调用取消或关闭时,都会调用 boost::asio::async* 函数的回调。通常,您只需使用 Stroustrup 钟爱的RAII模式在析构函数中进行适当的取消/关闭调用;任务完成。
但是,当所有者删除对象时不会调用析构函数,因为回调仍然保存 shared_ptrs 的副本,因此它们的 use_count 将大于零,从而导致资源泄漏。通过在删除对象之前进行适当的取消/关闭调用,可以避免泄漏。但这并不像使用 RAII 并在析构函数中进行取消/关闭调用那样万无一失。确保资源始终被释放,即使存在异常。
符合 RAII 的模式是使用静态函数进行回调,并在注册回调函数时将 weak_ptr 传递给 boost::bind,如下例所示:
class Connection : public boost::enable_shared_from_this<Connection>
{
boost::asio::ip::tcp::socket socket_;
boost::asio::strand strand_;
/// shared pointer to a buffer, so that the buffer may outlive the Connection
boost::shared_ptr<std::vector<char> > read_buffer_;
void read_handler(boost::system::error_code const& error,
size_t bytes_transferred)
{
// process the read event as usual
}
/// Static callback function.
/// It ensures that the object still exists and the event is valid
/// before calling the read handler.
static void read_callback(boost::weak_ptr<Connection> ptr,
boost::system::error_code const& error,
size_t bytes_transferred,
boost::shared_ptr<std::vector<char> > /* read_buffer */)
{
boost::shared_ptr<Connection> pointer(ptr.lock());
if (pointer && (boost::asio::error::operation_aborted != error))
pointer->read_handler(error, bytes_transferred);
}
/// Private constructor to ensure the class is created as a shared_ptr.
explicit Connection(boost::asio::io_service& io_service) :
socket_(io_service),
strand_(io_service),
read_buffer_(new std::vector<char>())
{}
public:
/// Factory method to create an instance of this class.
static boost::shared_ptr<Connection> create(boost::asio::io_service& io_service)
{ return boost::shared_ptr<Connection>(new Connection(io_service)); }
/// Destructor, closes the socket to cancel the read callback (by
/// calling it with error = boost::asio::error::operation_aborted) and
/// free the weak_ptr held by the call to bind in the Receive function.
~Connection()
{ socket_.close(); }
/// Convert the shared_ptr to a weak_ptr in the call to bind
void Receive()
{
boost::asio::async_read(socket_, boost::asio::buffer(read_buffer_),
strand_.wrap(boost::bind(&Connection::read_callback,
boost::weak_ptr<Connection>(shared_from_this()),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
read_buffer_)));
}
};
注意:read_buffer_
存储为shared_ptr
Connection 类中的 a 并作为 a 传递给read_callback
函数shared_ptr
。
这是为了确保在多个io_services
单独任务中运行的情况下,直到其他任务完成后,即调用函数时,才会删除 read_buffer_
。read_callback