2012-11-07 45 views
5

的正確初始化對於這樣的情況:智能指針數組

class A 
    { 
     //implementation 
    }; 

    class B 
    { 
    public: 
     B(); 
     ~B(); 
    private: 
     std::vector<std::shared_ptr<A>> _innerArray; 
    }; 

我應該在B()做創建具有有效狀態的對象?我是否需要爲數組中的每個A對象手動調用默認構造函數?我是否需要在~B()做一些特別的事情?如果B級是糟糕設計的例子,可以隨意說出如何讓它變得更好。謝謝。

編輯 因此,這裏是我真正需要的方案。

enter image description here

僅存儲在A的陣列和所有其他對象所以實值是用於存儲連接。 最簡單的示例 - A =點,B =通過選定點進行的線(或曲線)和C =通過線描述的平面。希望它使問題更加確切。

+1

完美檢查:你需要指針嗎?如果是這樣,它應該是一個共享指針? –

+0

B類應該有權訪問但不擁有其他地方存儲的某些對象。我沒有看到在這裏使用unique_ptr而不是shared_ptr,但我是智能指針的noob。 –

+0

@Pavel你是對的:你的場景排除使用'unique_ptr',它強制使用指針。但是,如果'B'不應該擁有所有權,我甚至會考慮使用原始指針而不是共享指針。畢竟,後者表示共享所有權(但也許這就是你最終需要的)。 –

回答

4

要在有效狀態下創建B對象,您不必再做任何事情。您甚至不必爲B聲明和實現構造函數和析構函數。 std::vector<std::shared_ptr<A>>B的成員將在B的構造函數中默認初始化,這意味着它在容器中還沒有任何元素。由於std::vectorstd::shared_ptr析構函數,它也將在~B中正確刪除。

另一方面,如果你想例如初始化它(即,3值),您可以在B的構造函數初始化列表中使用std::vectorstd::initializer_list構造函數。例如:

class B 
{ 
public: 
    B(): _innerArray{ std::make_shared<A>(), 
         std::make_shared<A>(), 
         std::make_shared<A>() } {} 
    ~B() {} 
private: 
    std::vector<std::shared_ptr<A>> _innerArray; 
}; 

記住std::make_shared使用完美轉發,所以你通過A的構造函數的參數作爲函數的參數,而不是類對象本身。

回答您對設計的關注我想鼓勵您在決定分享之前首先考慮向量中成員的獨佔所有權。

class B 
{ 
public: 
    B(); 
    ~B(); 
private: 
    std::vector<std::unique_ptr<A>> _innerArray; 
}; 

以上實施方式在許多方面更爲有效。首先,它讓你的設計更清晰地說明誰是負責A的使用壽命。 Next std::unique_ptr更快,因爲它不需要線程安全引用計數。最後但並非最不重要的是它不會花費任何額外的內存(與普通的C指針相比),而std::shared_ptr可能需要幾十個字節(24-48)來存儲共享狀態數據,這對於小型操作時非常無效。這就是爲什麼我總是使用std::unique_ptr作爲我的第一款度假智能指針,而當它真的需要時,我只能退回到std::shared_ptr

編輯:

回答您的編輯我將創建的類AB 3個容器,C。根據這一事實,如果你需要他們多態與否我將存儲一樣,要麼值(非多態類型):

std::deque<A> as; 
std::deque<B> bs; 
std::deque<C> cs; 

或(多態類型):

std::vector<std::unique_ptr<A>> as; 
std::vector<std::unique_ptr<B>> bs; 
std::vector<std::unique_ptr<C>> cs; 
的順序

as必須比bs長,bs必須長於cs)。然後我只需裏面的B類和std::vector<B*>裏面的C類沒有任何智能指針的使用。

我希望有幫助。

編輯:

在其允許的引用第一殼體改變std::vectorstd::deque /指針容器元素生存容器與擴展push_back()。然而,他們將無法生存擦除元素,排序或其他東西。

+0

很棒的回答。完善。 –

2

如果你這樣做,矢量的大小爲零,即內容被正確地初始化。如果矢量大小正確(例如,在矢量上調用resize之後),則每個元素都將被正確初始化。由於元素是shared_ptr s,將會調用shared_ptr的默認構造函數,這意味着您最終將得到一個空指針向量。

如果你想將內容從另一個容器複製,使用矢量構造函數的迭代版本:

B (SomeContainerTypeContainingSharedPointers container) 
: _innerArray (container.begin(), container.end()) { 
} 

如果您不想初始化從容器的載體,而是從別的地方(例如,快速創建對象) - 自己編寫一個輸入迭代器類型(即,一種「工廠迭代器」)。

1

該向量爲空,因此您不必在默認構造函數中執行任何特殊操作。而且你也不需要在B()中做任何事情。當向量的析構函數被調用時,shared_ptrs的引用計數將自動減少。

1

Bt默認std::shared_ptr<A>將用NULL填充內部ptr。要創建智能指針使用std::make_shared

_innerArray.push_back(std::make_shared<A>(/*constructor params here*/)); 

但在你的例子向量是空的。

0

默認構造函數已經完成了所有需要的操作。你甚至可以離開B()沒有任何損失。