C++ Boost异步函数和共享ptr';s
我经常在代码中看到这种模式,将C++ Boost异步函数和共享ptr';s,c++,boost,boost-asio,shared-ptr,C++,Boost,Boost Asio,Shared Ptr,我经常在代码中看到这种模式,将shared\u从\u this绑定为成员函数的第一个参数,并使用async.*函数分派结果。下面是另一个问题的例子: void Connection::Receive() { boost::asio::async_read(socket_,boost::asio::buffer(this->read_buffer_), boost::bind(&Connection::handle_Receive,
shared\u从\u this
绑定为成员函数的第一个参数,并使用async.*
函数分派结果。下面是另一个问题的例子:
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));
}
使用shared\u from_this()
而不是this
的唯一原因是在调用成员函数之前保持对象的活动状态。但除非有某种增强魔法,因为这个
指针属于连接*
类型,这就是handle\u Receive
可以接受的所有内容,返回的智能指针应该立即转换为常规指针。如果发生这种情况,就没有任何东西可以让这个物体存活。当然,从这个调用shared\u没有指针
然而,我经常看到这种模式,我不敢相信它会像我看来的那样彻底崩溃。操作完成后,是否有一些Boost魔法可以使共享的\u ptr转换为常规指针?如果是这样,是否有文件记录
特别是,是否有文档记录共享指针在操作完成之前将一直存在?在强指针上调用get_pointer
,然后在返回的指针上调用成员函数是不够的,除非在成员函数返回之前强指针没有被销毁。也许我在这里遗漏了一些明显的东西,但是shared_从\u this()返回的共享ptr
存储在由boost::bind
返回的函数对象中,该函数对象使其保持活动状态。它仅在异步读取完成后启动回调时隐式转换为连接*
,并且对象至少在调用期间保持活动状态。如果handle\u Receive
没有从此创建另一个共享\u ptr,并且存储在bind functor中的共享\u ptr是最后一个活着的共享\u ptr,则在回调返回后对象将被销毁。没有从boost::shared\u ptr
的转换(返回类型为shared\u from\u this
)连接*
(此的类型),因为正如您正确指出的那样,这是不安全的
魔法在Boost.Bind中。简单地说,在形式为bind(f,a,b,c)
的调用中(本例中不涉及占位符或嵌套绑定表达式),其中f
是指向成员的指针,则调用调用结果将导致形式为(a.*f)(b,c)的调用
如果a
具有从指向成员的指针的类类型派生的类型(或类型boost::reference_wrapper
),或者其形式为(*a.*f)(b,c)
。这同样适用于指针和智能指针。(我实际上是在记忆中使用std::bind
,Boost.bind的规则并不完全相同,但两者的精神是相同的。)
此外,this()的shared\u的结果存储在调用bind
的结果中,确保没有生命周期问题。如下所示:
1) Boost.Bind文档:
“[注:mem_fn创建能够接受
指向对象作为其第一个对象的指针、引用或智能指针
参数;有关其他信息,请参阅mem_fn文档。]”
2) mem_fn文件:
调用函数对象时,第一个参数x为
既不是指向相应类的指针,也不是对该类的引用(在
上面的示例),它使用get_指针(x)从x获取指针。
库作者可以通过以下方式“注册”他们的智能指针类
提供适当的get_指针重载,允许mem_fn
承认并支持他们
因此,指针或智能指针将按原样存储在活页夹中,直到其被调用。简而言之,boost::bind
创建一个boost::shared_ptr
的副本,该副本从shared___this()
返回,boost::asio
可以创建处理程序的副本。处理程序的副本将保持活动状态,直到发生以下情况之一:
- 处理程序已被调用服务的
run()
、run\u one()
、poll()
或poll\u one()
成员函数的线程调用
io\u服务
已销毁
- 拥有处理程序的
io_service::service
通过关闭
以下是文件的相关摘录:
- boost::bind:
bind
获取的参数由返回的函数对象在内部复制和保存
- boost::asio:
io_服务
保证仅在当前调用了run()
、run_one()
、poll()
或poll_one()
成员函数的线程中调用处理程序。[…]io_服务将根据需要制作处理程序对象的副本
- boost::asio:
计划在
io\u服务
上延迟调用的未调用处理程序对象或任何相关串将被销毁。
如果对象的生存期与连接的生存期(或某些其他异步操作序列)相关联,则对象的共享\u ptr
将绑定到与之关联的所有异步操作的处理程序中。[…]当单个连接结束时,所有关联的异步操作都将完成。相应的处理程序对象被销毁,所有对对象的共享\u ptr
引用也被销毁
虽然日期为(2007年),但其来源于Boost.Asio。第5.3.2.7节。异步操作的要求
为
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_)));
}
};