我正在使用 boost::asio。我写了一个负责从套接字异步读取的类。
在我的应用程序中,io_service 可以在一个应用程序运行期间多次停止和启动。
所以我不得不担心服务停止时的内存泄漏。
我想到了两个解决方案:

  • 请求异步请求的类为函数提供了一个用于asio读取的缓冲区,并负责其释放。这是一个显而易见的解决方案,但我不喜欢它。将不需要的参数传递给函数看起来真的很奇怪。
  • 绑定(bind)到回调的智能指针。这里的例子:
    http://pastebin.com/p8nQ5NFi

  • 现在我正在使用第二个解决方案,但无论我感觉如何,我正在发明一个轮子。异步调用中缓冲区清理的常见做法是什么?我的方法有什么隐藏的问题吗?

    最佳答案

    shared_ptr 方法相当普遍。但是,不是将 shared_ptr 作为附加参数传递给 bind ,而是可以将 shared_ptr 作为实例对象传递来代替 this

    boost::shared_ptr< my_class > ptr( this );
    
    boost::asio::async_read( stream, buffer,
      boost::bind( &my_class::read_handler, ptr,
         boost::asio::placeholders::error
         boost::asio::placeholders::bytes_transferred ) );
    

    通常,由于实例将通过 shared_ptr 进行管理,它可能在也可能不在 this 的上下文中,因此使用 Boost.SmartPointer 的 enable_shared_from_this 是个好主意。当一个类从 boost::enable_shared_from_this 继承时,它提供了一个 shared_from_this() 成员函数,该函数将一个有效的 shared_ptr 实例返回给 this
    class my_class: public boost::enable_shared_from_this< my_class >
    {
      void read()
      {
         boost::asio::async_read( stream, buffer,
           boost::bind( &my_class::read_handler, shared_from_this(),
              boost::asio::placeholders::error
              boost::asio::placeholders::bytes_transferred ) );
      }
    };
    
    boost::shared_ptr< my_class > foo( new my_class() );
    foo->read();
    

    在这个片段中,foo.get()foo->shared_from_this() 都指向同一个实例。这有助于防止难以定位的内存泄漏。例如,在原始示例代码中,如果 Protocol::AsyncReadMessage 的复制构造函数在尝试调用 AsyncReadHandler 时抛出异常,则 AsyncReadMessage 中会发生内存泄漏。 Boost.Asio 的 asynchronous TCP daytime server 和许多 examples 显示在 Boost.Asio 中使用的 enable_shared_from_this。为了更深入的理解,this 问题专门涵盖了异步 Boost.Asio 函数和 shared_ptr

    此外,在原始代码中,将 Protocol::AsyncHelper 设为模板类可能更容易,而不是将其设为具有模板成员函数的非模板化类。这将允许 AsyncHelper 接受协议(protocol)、流和处理程序作为构造函数参数,将它们存储为成员变量。此外,它使 bind 调用更容易阅读,因为它减少了需要传递的参数数量,并且由于成员函数不再是模板,因此无需指定它们的完整类型。 Here 是一个例子的快速传递。

    关于C++ 异步调用最佳实践,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11641620/

    10-11 22:42
    查看更多