2016-03-06 28 views
0

使用來自boost::asio的異步I/O操作我經常需要共享指針(回調中使用enable_shared_from_thisshared_from_this)以避免過早刪除對象。 我認爲它可以通過保持在課堂上unique_ptr或只是對象(所有權)(作爲成員)異步I/O操作 - 避免刪除對象的正確方法

例如進行: 只有foo方法使用sender

1日(流行的解決方案):

class C { 
    public: 
    void foo 
    { 
     std::shared_ptr<Sender> sender = std::make_shared<Sender>(); 
     sender->send(); 
     // class Sender use async_write 
     // inheritance: enable_shared_from_this 
     // callback in async operation created with argument shared_from_this 
    } 
}; 

爲什麼沒有人用這個解決方案(?):

class D { 
public: 
    void foo 
    { 
     sender.reset(new Sender); 
     sender->send(); 
    } 
private: 
    std::unique_ptr<Sender> sender; 
}; 

我知道,發件人將不會被刪除早期到。我沒有shared_ptrs。我認爲避免它們是很好的,因爲如果發件人類中的回調也使用異步操作,我需要另一個共享指針等。我認爲D類閱讀更友好。 但我不知道它是否是一種很好的風格......我總是在網上看到shared_ptrs的解決方案。

+0

您使用了以錯誤方式共享的make。 – mustafagonul

+0

在這種情況下,您爲什麼認爲避免'shared_ptr'是好事? –

回答

0

對一個對象只能有一個unique_ptr。如果您的發送和接收操作都處於待處理狀態,會發生什麼情況?如果你有一個接收操作和一個計時器會發生什麼?

是的,你可以使用unique_ptr,但是你必須實現你自己的未完成操作數。您必須以線程安全的方式遞增和遞減計數。而且你必須經常檢查這個計數是否爲零來調用析構函數。爲了清理這些,你可能會把所有這些功能綁定到它自己的類中。而且你已經改造了shared_ptr

0

後者的用法很脆弱,不能保證發件人不會被過早刪除。例如,考慮在異步操作完成之前連續調用D::foo()的情況。

public: Sender 
{ 
public: 
    void send() 
    { 
    boost::asio::async_write(socket_, boost::asio::buffer(buffer_), ...); 
    } 
private: 
    std::array<char, 64> buffer_; 
    boost::asio::ip::tcp::socket socket_; 
    ... 
}; 

D d; 
d.foo(); // Create Sender1, initiate async_write. 
d.foo(); // Delete Sender1, create Sender2, initiate async_write. 
io_service.run(); // Sender1's async_write invokes undefined behavior. 

在上面的代碼,以第二個電話會刪除具有出色的操作,導致不確定的行爲第一Sender對象:以前Sender對象可以與可依賴的Sender對象上未完成的操作被刪除。另一方面,如果Sender繼承自enable_shared_from_this,並且shared_from_this()的結果被綁定到異步操作的處理程序,那麼Sender對象的生命週期將延長至少與操作一樣長。

0

你看過asio :: spawn嗎?基本上,它使用異步C++編程的大部分複雜性,並允許您將對象放在堆棧上。

下面是一個簡單的例子:modern.cpp

使用這種方法節省了大量的實現和調試異步應用程序的時間,而且它使代碼很容易理解。 (我曾經使用傳統的回調函數實現了一個RTP over TCP代理,事後證明這是一個噩夢)。

關於分片與獨特的指針 - 我的經驗是共享指針更容易與asio一起使用。在移動獨特指針時存在一些問題,並且當程序變得稍微複雜時,犯錯誤錯誤確實很容易。我認爲我會堅持使用共享和弱指針作爲默認值 - 並且只能切換到探查器輸出的對象的唯一指針,這表明它是值得的。

相關問題