2016-11-07 26 views
3

假設我有一個Foo對象的集合,並且每個Foo擁有一個或多個Bar對象。特定的FooBar可以被我的界面的用戶刪除;當一個Foo被刪除時,它所擁有的所有Bar也被刪除。到目前爲止,每個Foo集合unique_ptr<Bar>是我需要自動管理這個模型。但是,我有一個額外的要求:一旦Foo沒有任何Bar,它也應該被刪除。如何優雅地使用智能指針來模擬C++中的複雜生命週期?

當然,我可以直接寫代碼來明確地處理這個問題,但是我想知道是否有一種更習慣的方式來實現同樣的目的。聽起來是個極像是shared_ptr,但不太...

+1

誰擁有'Foo'收藏?這可能是刪除Foos應該去的地方。 – drRobertz

+0

你應該通過代碼強制這個條件,這是非常具體的,我懷疑你會找到一個「優雅」的慣用方法。只是設計一個音響系統 – Dredok

+0

@亞倫Tausky:請看看我的文章,並將其標記爲您的問題的確切答案! – Roland

回答

1

由於刪除所有Bar期從一個Foo應該刪除Foo,它可能確實聽起來像是你需要的shared_ptr期從Bar秒的極少數的Foo

然而,該模型將置於其Bar S的手Foo的生命週期:你將無法直接刪除Foo,而是你必須追捕所有Bar S和刪除這些

Foo將保持Bar* s,而不是unique_ptr<Bar> S,因爲它不能前的Bar小號死亡。但你必須給Bar S的所有權有人 ...

你可能會與另一個對象最終持有的unique_ptr<Bar>及其對應於每個Foo S的集合,但你必須要保持所有這一切同步,因爲Bar來來去去。這是你試圖避免的同一種記賬方式,但是結果會更大,更復雜和更脆弱,因爲內存泄漏和流氓指針會成爲失敗案例。


所以不是所有這一切,我建議你堅持你的第一unique_ptr -Powered想法。在實施中的第一步可能看起來像這樣:

struct Foo { 
private: 
    friend void remove(std::unique_ptr<Foo> &foo, Bar const *bar); 

    // Removes the bar from this Foo. 
    // Returns true iff the Foo is now empty and should be deleted. 
    bool remove(Bar const *bar) { 
     auto i = std::find_if(begin(_bars), end(_bars), [&](auto const &p) { 
      return p.get() == bar; 
     }); 

     assert(i != end(_bars)); 
     _bars.erase(i); 

     return _bars.empty(); 
    } 

    std::vector<std::unique_ptr<Bar>> _bars; 
}; 

// Removes the bar from the Foo. 
// Deletes the Foo if it becomes empty. 
void remove(std::unique_ptr<Foo> &foo, Bar const *bar) { 
    if(foo->remove(bar)) 
     foo.reset(); 
} 
1

沒有慣用的解決方案。使用aggregate和weak_ptr內部的shared_ptr和unique_ptr作爲聚合的錨點。這是我的你的問題的詳盡的例子:

#include <memory> 
#include <iostream> 
#include <vector> 
using std::cout; 
using std::endl; 
using std::vector; 
using std::shared_ptr; 
using std::unique_ptr; 
using std::weak_ptr; 
using std::make_shared; 
using std::make_unique; 

struct Foo; 
struct Bar 
{ int b; 
    shared_ptr<Foo> f; 
    Bar(int b, shared_ptr<Foo> f): b(b), f(f) { cout << "Constructor B with: " <<b << std::endl; } 
    ~Bar() { cout << "Destructor B with: " <<b << endl; } 
}; 
struct Foo 
{ 
    Foo() { cout << "Constructor Foo" << endl; } 
    ~Foo() { cout << "Destructor Foo" << endl; } 
    void clear() { vb.clear(); } 
    vector<unique_ptr<Bar>> vb; 
}; 


int main(int argc, char* argv[]) 
{ weak_ptr<Foo> wf; // Anchor to Aggregate 
    { // Construction of Aggregate 
     vector<shared_ptr<Bar>> vb2; 
     shared_ptr<Foo> f =std::make_shared<Foo>(); 
     f->vb.emplace_back(make_unique<Bar>(1, f)); 
     f->vb.emplace_back(make_unique<Bar>(2, f)); 
     wf =f; 
    } 
    shared_ptr<Foo> f3 =wf.lock(); 
    if (f3) 
    { 
     if (argv[1][0] =='f') 
     { 
      cout <<"Destroy Foo" <<endl; 
      f3->clear(); 
     } 
     if (argv[1][0] =='b') 
     { 
      cout <<"Destroy Bar" <<endl; 
      f3->vb[0].reset(); 
      f3->vb[1].reset(); 
     } 
    } 
} 

調用該程序參數「F」或「b」和輸出將是:

Constructor Foo 
Constructor B with: 1 
Constructor B with: 2 
Destroy ??? 
Destructor B with: 1 
Destructor B with: 2 
Destructor Foo