Boost Asio - 使用shared_ptr处理解析器和套接字

时间:2012-02-07 13:57:46

标签: c++ sockets boost boost-asio shared-ptr

我有一个能够通过TCP调度消息的类。这里是简化的界面:

class CommandScreenshot : public CameraCommand
{
public:
    CommandScreenshot();
    ~CommandScreenshot();
    void Dispatch(boost::shared_ptr<boost::asio::io_service> io_service);

 private:
     void resolve_handler(const boost::system::error_code& err,
          boost::asio::ip::tcp::resolver::iterator endpoint_iterator);

};

正如您所看到的,我有一个函数Dispatch,它实际上只是为了启动异步操作:

void CommandScreenshot::Dispatch(boost::shared_ptr<boost::asio::io_service> io_service)
{
    boost::asio::ip::tcp::resolver resolver(*io_service);
    boost::asio::ip::tcp::resolver::query query(m_hostname,"http");
    resolver.async_resolve(query,boost::bind(&CommandScreenshot::resolve_handler,this,boost::asio::placeholders::error, boost::asio::placeholders::iterator));
    return;
}

其他所有内容都将在以下回调函数中完成。 io_service对象以及相应的线程由另一个类(其实例为CommandScreenshot并且调用Dispatch函数)管理。

现在要使用Boost实现简单的TCP连接,您需要一个resolver和一个socket对象,它们都绑定到io_service对象。由于io_service对象只会在当时传递,因此调用该函数,我无法在类构造函数中初始化它们。 此外,不可能将它们声明为类成员,然后只在函数本身中初始化它们。

我的第一个想法是在函数调用时初始化它们并将它们传递给我的完成处理程序。这意味着我每次调用函数时都声明两个对象并将它们绑定到io_service。然后在async_resolve,我通过boost::bind添加两个参数作为参数。这意味着我的resolve_handler会期望更多的论点 - 例如:

void resolve_handler(const boost::system::error_code& err,
          boost::asio::ip::tcp::resolver::iterator endpoint_iterator,
          boost::asio::ip::tcp::resolver resolver,
          boost::asio::ip::tcp::socket socket);

我实际上怀疑这是一个体面和公平的解决方案。通常这些对象应该保留为成员而不是被复制 - 所以我给了它另一个想法,我的思想把我带到了boost::shared_ptr

在我的标题中,它现在看起来像这样:

// Stuff above stays the same
private:
  boost::shared_ptr<boost::asio::ip::tcp::resolver> m_resolver;
  boost::shared_ptr<boost::asio::ip::tcp::socket> m_socket;
// Stuff below stays the same

实施将是:

void CommandScreenshot::Dispatch(boost::shared_ptr<boost::asio::io_service> io_service)
{
    m_resolver.reset(new boost::asio::ip::tcp::resolver(*io_service));
    m_socket.reset(new boost::asio::ip::tcp::socket(*io_service));
    boost::asio::ip::tcp::resolver::query query(m_hostname,"http");
    m_resolver->async_resolve(query,boost::bind(&CommandScreenshot::resolve_handler,this,boost::asio::placeholders::error, boost::asio::placeholders::iterator));
    return;
}

有了这个,我不需要复制4个(或者甚至更多)参数并将它们绑定在一起。当我需要套接字对象时,我可以通过指针访问它,这是一个类成员。

现在我的简单问题是 - &gt;这是正确的方法吗?即使异步部分未完成,也可以多次调用该函数。 (我知道我应该使用互斥锁来保护套接字和解析器)。但这是否干净,我每次调用Dispatch函数时都会创建一个新对象? reset调用是否足以摆脱任何不必要的内存?

我知道这是一个特定简短问题的长文本,而且甚至没有错误。但我总是想知道我是不是一个体面的方式,如果有更好的方式,我会怎么做。

1 个答案:

答案 0 :(得分:3)

将memebers定义为asio对象的shared_ptr的想法是可以的。但你不应该摧毁&amp;每次都创造它们:

if (!m_resolver)
{
  m_resolver.reset(...);
}

此外,如果确保asio对象上的所有操作都发生在运行io_service的线程中(假设每个io_service都有一个线程),则可以避免显式锁定。为此,只需分离接口函数的实现并使用post()。当然,使用shared_from_this惯用法来简化对象生命周期控制:

void CommandScreenshot::someMethod(Arg1 arg1, Arg2 arg2)            
{
  io_.post(bind(&CommandScreenshot::someMethodImpl, shared_from_this, arg1, arg2)); 
}
//...
void CommandScreenshot::someMethodImpl(Arg1 arg1, Arg2 arg2)            
{
  // do anything you want with m_resolver, m_socket etc.
}