Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Boost异步函数和共享ptr';s_C++_Boost_Boost Asio_Shared Ptr - Fatal编程技术网

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_)));
  }
};