2012-02-07 94 views
4

我有應能夠通過TCP調度信息的一類。在這裏,簡化接口:升壓短耳 - 處理解析器和插座與shared_ptr的

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連接,您需要一個resolversocket對象,它們都綁定到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(或者甚至更多)參數並將它們綁定在一起。當我需要socket對象時,我可以通過指針來訪問它,這是一個類成員。

現在我簡單的問題 - >這是正確的方式去?即使異步部分未完成,也可以多次調用該函數。 (我知道我應該用互斥鎖保護套接字和解析器)。但是這是乾淨的,當我打電話給Dispatch功能時,我每次都會創建一個新對象?調用reset足以擺脫任何不需要的內存嗎?

我知道這是一個特定的短問題的長文本,此外甚至沒有錯誤。但我總是想知道,如果這是一種體面的方式,如果有更好的方式,我該怎麼做。

回答

3

將成員定義爲shared_ptr到asio對象的想法是可以的。但你不應該破壞&創建它們再次每次:

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. 
}