C++11 从\u启用\u共享\u这对共享\u ptr的使用寿命有何影响?
我正在看boost::asio的一个教程C++11 从\u启用\u共享\u这对共享\u ptr的使用寿命有何影响?,c++11,shared-ptr,C++11,Shared Ptr,我正在看boost::asio的一个教程 class tcp_server { public: tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13)) { start_accept(); } private: void start_accept() { tcp_connection::poin
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
{
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service()); // shared_ptr got created.
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error)); // instance added to io_service task list, but bind does not use shared_ptr internally I believe.
} // shared_ptr of tcp_connection goes out of scope.
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
}
start_accept();
}
class tcp_connection
: public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
message_ = make_daytime_string();
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
private:
tcp_connection(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
void handle_write(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
{
}
tcp::socket socket_;
std::string message_;
};
class-tcp\u服务器
{
公众:
tcp_服务器(boost::asio::io_服务和io_服务)
:acceptor_(io_服务,tcp::endpoint(tcp::v4(),13))
{
开始接受();
}
私人:
void start_accept()
{
tcp_连接::指针新建_连接=
tcp_connection::create(acceptor_u.get_io_service());//已创建共享的ptr。
acceptor\异步\u accept(新建\u连接->套接字(),
boost::bind(&tcp\u server::handle\u accept,这个,新的\u连接,
boost::asio::placeholders::error));//实例已添加到io_服务任务列表中,但我相信bind在内部不使用共享_ptr。
}//tcp_连接的共享_ptr超出范围。
无效句柄\u接受(tcp\u连接::指针新\u连接,
常量boost::系统::错误(代码和错误)
{
如果(!错误)
{
新建连接->开始();
}
开始接受();
}
类tcp\u连接
:public boost::从\u启用\u共享\u
{
公众:
typedef boost::共享_ptr指针;
静态指针创建(boost::asio::io_服务和io_服务)
{
返回指针(新的tcp_连接(io_服务));
}
tcp::套接字和套接字()
{
返回插座;
}
void start()
{
message_uu=make_daily_string();
boost::asio::异步写入(套接字),boost::asio::缓冲区(消息),
boost::bind(&tcp_connection::handle_write,shared_from_this(),
boost::asio::占位符::错误,
boost::asio::占位符::字节(已传输);
}
私人:
tcp_连接(boost::asio::io_服务和io_服务)
:socket_(io_服务)
{
}
无效句柄写入(常量boost::system::error\u代码&/*error*/,,
大小\u t/*字节\u传输*/)
{
}
tcp::socket-socket;
std::字符串消息;
};
我发现有一部分运行时,tcp\u connection
对象的shared\u ptr
对象没有活动。这似乎意味着tcp\u connection
对象将在该部分开始时被破坏,因为它的shared\u ptr
中的计数降为零,这显然不是什么我们想要
但是后来我在类tcp\u连接中看到了注释
我们将使用shared_ptr并从_启用_shared_,因为我们希望保持tcp_连接对象的活动状态,只要存在引用它的操作
我也搜索了这个问题,并在SO中得到了一个Q&a。但我仍然对标题问题感到困惑。具体地说,有一个操作引用它是什么意思?tcp\u server::start\u accept()时
返回,tcp\u连接
的所有shared\u ptr
实例应超出范围,并且可能只有一些原始指针引用添加到io\u服务
任务列表中。如果没有实例,如何从该
启用\u shared\u防止tcp\u连接
的堆实例被破坏这个tcp\u连接
对象的shared\u ptr
?或者它与从这个对象启用的\u shared\u无关,但是boost::asio::io\u服务
在内部保持有界异步\u处理程序的shared\u ptr这个问题可以通过描述shared\u ptr的非侵入性设计来回答,它可以让我ans不接触其指向对象的“任何”代码
我们可以从它的非侵入式设计中得到很多好处。但另一方面,它不可避免地导致了这样的情况:一旦共享了\u ptr,就到处共享了\u ptr,而没有原始指针。
让我们看看这个片段:
{
shared_ptr<int> orig_sp{new int};
shared_ptr<int> good_sp{orig_sp}; // it's ok
shared_ptr<int> bad_sp{orig_sp.get()}; // leads crashing
}
但问题是共享\u ptr
ed对象的成员函数想要延长其自身的生命周期
class tcp_connection {
void start()
{
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, (/* how to fill this field? */),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
};
- 在该字段中填写
此
是不可接受的,因为它不会延长tcp\U连接的生命周期
- 填充
boost::shared_ptr(此)
也是不可接受的。根据我们的第一个代码片段,它将导致崩溃
- 也许
boost::shared\u ptr(tcp\u connection::create(acceptor.get\u io\u service())
看起来不错,但它试图在其成员中创建对象本身
现在很清楚了。tcp\u connection::start()
想知道哪个共享ptr被管理,但根据共享ptr的非侵入性设计,tcp\u connection
不应该包含共享ptr的任何信息。这是不可能的任务
最后,我们必须妥协,并请求enable\u shared\u from\u this
寻求帮助。enable\u shared\u from\u this
要求必须使用从中派生类。这就是tcp\u连接
看起来非常棘手的原因
class tcp_connection : boost::enable_shared_from_this<tcp_connection> {
void start()
{
// ...
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
};
class-tcp\u连接:boost::从\u启用\u共享\u{
void start()
{
// ...
boost::asio::异步写入(套接字),boost::asio::缓冲区(消息),
boost::bind(&tcp_connection::handle_write,shared_from_this(),
boost::asio::占位符::错误,
boost::asio::占位符::字节(已传输);
}
};
enable_shared_from_this
模板为共享_ptr保留了一些字段,如引用计数,并为那些成员函数希望使用共享_ptr而不是this
的函数提供了shared_from_this
对象由functor保持活动状态
请注意,handle\u accept
回调函数如何将shared\u ptr
到tcp\u连接
作为参数。魔法现在发生在boost::bind
调用中,该调用用于指定对async\u accept
的回调
该bind调用返回一个functor对象,该对象按值存储调用handle\u accept
所需的所有参数。因此,bind返回的functor包含shared\u ptr
到tcp\u连接的副本,从而使其保持活动状态。functor(将其视为boost::function
)现在依次由t复制
class tcp_connection : boost::enable_shared_from_this<tcp_connection> {
void start()
{
// ...
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
};