2017-07-26 128 views
3

我正在設計一個基於virtual方法的C++類接口,以便能夠提供可擴展性點。std :: unique_ptr和std :: shared_ptr作爲虛函數的參數

很多這些公共方法都需要heap分配的對象作爲參數。

由於我正在使用現代C++模式,因此我打算使用std::unique_ptrstd::shared_ptr,但我對它們都有疑問。

使用std ::的unique_ptr看起來是這樣的:

class IFoo { 
    virtual void doSomethingWithUser(std::unique_ptr<User> user) = 0; 
} 

強制調用者提供std::unique_ptr有缺點:

  • 主叫不能做,因爲它提供的用戶進行任何操作必須移動
  • 如果任何doSomethingWithUser實現需要將用戶存儲在某個容器中,則不能從std::shared_ptr

對所有公共方法使用std::shared_ptr可以解決問題,但我們必須支付額外的內存空間以及引用計數的原子增量和減量。

有沒有我可以遵循的經驗法則?

+2

「很多這些公共方法都需要堆分配對象作爲參數。」咦?那是什麼意思? –

+0

@FredLarson如上例所示,用戶是堆分配的,它並不在棧中。 (用戶不可複製,因此需要堆分配它) – steazzalini

+2

我沒有看到什麼堆與堆棧分配有什麼關係。你的意思是你需要傳遞指針(或引用)而不是傳值? –

回答

6

如果doSomethingWithUser不需要所有權,則不應將其轉移到此方法。

確實,複製共享指針或移動唯一指針可以有效地傳輸資源的所有權。

您的函數參數應反映您對傳遞資源的假定所有權的意圖。

如果您只需要觀察該值並對其進行變異,則應將非擁有的句柄傳遞給函數。

如果您需要保持資源活着並可能將其刪除,那麼您應該傳遞擁有的句柄,無論它是否共享它的唯一所有權。

在你的情況下,函數的名稱告訴我你需要「對用戶做某事」,而不包含它傳遞調用者的生命期。所以你應該通過一個非擁有的句柄。該句柄可以是User*User&,甚至可以是std::reference_wrapper<User>boost::optional<User&>,具體取決於您的需要。

您的界面應該確實表達一個對象應該能夠做什麼,並確實強制每個函數應該使用哪些參數,但是您的界面還應該表達它對它的參數擁有什麼所有權。

我通常更喜歡引用,因爲它們確保它不能爲空,並且能夠在自動存儲中使用對象。有些人可能會爭辯說,他們更喜歡原始指針作爲非空非擁有句柄,但我強烈反對,因爲他們強制&object語法,並允許爲空。

非擁有原始指針沒有問題。但是,現代C++中不應該使用原始擁有指針。

+0

您可能還會提到weak_ptr,因爲這是該函數使用但不保留數據所有權的語義指示。 – wphicks

+0

>我通常更喜歡引用,因爲它們確保它不能爲null,並且在自動存儲中可以很好地與對象一起工作,但它主要是一個品味問題。呃,不是。在你突變對象的罕見情況下,會出現某種糟糕的,誤導性的說法(半開玩笑)。但是,通過指向const的指針而不是const指針而不是null的東西太可怕了,而且根本就不是味道。 –

+2

@wphicks'std :: weak_ptr'仍然是共享所有權,但仍然是非擁有的句柄。 –

相關問題