调用socket.close()不会破坏套接字。但是,应用程序可能需要管理操作和完成处理程序所依赖的对象的生存期,但这不一定是套接字对象本身。例如,考虑一个client类,它持有一个缓冲区、一个套接字,并且有一个未完成的读操作,其完成处理程序为client::handle_read()。可以close()并显式地销毁套接字,但是至少在调用处理程序之前,buffer和client实例必须保持有效:
代码语言:javascript运行复制class client
{
...
void read()
{
// Post handler that will start a read operation.
io_service_.post([this]() {
async_read(*socket, boost::asio::buffer(buffer_);
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
});
}
void handle_read(
const boost::system::error_code& error,
std::size_t bytes_transferred
)
{
// make use of data members...if socket_ is not used, then it
// is safe for socket to have already been destroyed.
}
void close()
{
io_service_.post([this]() {
socket_->close();
// As long as outstanding completion handlers do not
// invoke operations on socket_, then socket_ can be
// destroyed.
socket_.release(nullptr);
});
}
private:
boost::asio::io_service& io_service_;
// Not a typical pattern, but used to exemplify that outstanding
// operations on `socket_` are not explicitly dependent on the
// lifetime of `socket_`.
std::unique_ptr
std::array
...
}
应用程序负责管理操作和处理程序所依赖的对象的生存期。chat client example通过在线程join()中等待io_service.run()返回来保证chat_client实例在不再使用后被销毁,从而实现了这一点
代码语言:javascript运行复制int main(...)
{
try
{
...
boost::asio::io_service io_service;
chat_client c(...);
std::thread t([&io_service](){ io_service.run(); });
...
c.close();
t.join(); // Wait for `io_service.run` to return, guaranteeing
// that `chat_client` is no longer in use.
} // The `chat_client` instance is destroyed.
catch (std::exception& e)
{
...
}
}管理对象生存期的一种常见方式是让I/O对象由继承自enable_shared_from_this<>的单个类管理。当类从enable_shared_from_this继承时,它提供一个shared_from_this()成员函数,该函数返回管理this的有效shared_ptr实例。shared_ptr的副本被传递给完成处理程序,比如lambda中的捕获列表,或者作为实例句柄传递给bind(),导致I/O对象的生命周期至少和处理程序一样长。有关使用此方法的示例,请参阅Boost.Asio asynchronous TCP daytime server教程。