2011-04-18 70 views
4

在我的代碼遵循兩個規則,當談到intrusive_ptrs:這是intrusive_ptr的有效用法嗎?

  • 按值傳遞原始指針意味着原始指針保證了功能的生命週期內是有效的。
  • 如果原始指針要在函數的生命週期之外存儲和使用,它應該存儲在intrusive_ptr中。

許多互聯網評論員寫道,除了使用第三方代碼之外,shared_ptr應該優先於intrusive_ptr。然而,intrusive_ptr避免傳遞智能指針,因爲您可以從原始指針創建intrusive_ptr,因爲在該函數的生命週期之外需要該對象。

我只是擔心,我失去了一些東西,因爲什麼,我讀過取得了這點約intrusive_ptrs,而且大多數人似乎使用enable_shared_from_this時喜歡shared_ptrs即使他們引進的內存開銷,同時問題和遺產。

+2

其中一個注意事項:如果該對象在函數期間保證有效,那麼我寧願傳遞一個引用,這意味着沒有所有權問題。它更自我記錄。 – 2011-04-19 06:34:22

回答

9

在具有所有權語義的公共API中傳遞原始指針應該很少,只有在絕對必要時才能完成。例如。與您的界面無法更改的代碼進行交互。

在私有API中傳遞原始指針,例如在一個班級的成員內部是沒有問題的。

考慮以下三個功能:

void f(A* a); 
void g(std::unique_ptr<A> a); 
void h(std::shared_ptr<A> a); 

f所有權語義不明確。如果您是f的客戶,則需要閱讀文檔以確定f是否將取消分配a,或忽略a的所有權問題。

g的所有權語義是明確的。當您致電g時,您將a的所有權轉讓給g,您不再對此負責。 g將取消分配a或將該資源的所有權轉移到別處。

h的所有權語義很清楚。當您撥打h時,您和h成爲a的共同所有者。最後一個關閉燈。

void q(boost::intrusive_ptr<A> a); 

q具有相同的所有權語義h。主要的區別是,必須存在以下免費功能:

intrusive_ptr_add_ref(A*); 
intrusive_ptr_release(A*); 

如果你是f作者和你打電話a這些功能,你應該記錄你這樣做。你的客戶不一定知道你是誰。如果您是f的客戶,則無法知道f是否會調用這些功能,除非您閱讀其文檔。

如果您是f的作者,並且打算撥打intrusive_ptr_*函數,則可以通過編寫代碼q來明確地在您的界面中進行此操作。

但通常沒有強迫A編寫intrusive_ptr_*函數的作者的強制性理由。通過編寫h,您可以獲得與q相同的所有權語義,而不會對A強加任何的進一步需求。

在內存開銷

如果您創建shared_ptr有:

shared_ptr<A> p = make_shared(arguments-to-construct-an-A); 

那麼你shared_ptr將擁有完全相同的內存開銷爲intrusive_ptr。該實現將在相同的內存分配中分配A和refcount。您的客戶不需要知道或關心您的shared_ptr如此有效地構建。

+3

如果使用'make_shared'創建'shared_ptr',那麼你寫'shared_ptr'將具有與'intrusive_ptr'完全相同的內存開銷*。你可能是想寫*相同數量的分配*? AFAIK,'shared_ptr'實例至少佔用相應'intrusive_ptr'實例的空間的兩倍,並且'shared_pointer'的相關引用計數器也至少是'intrusive_ptr'的計數器的兩倍(因爲shared_ptr '也必須鏈接'weak_ptr'實例)。 – 2012-01-31 23:02:01

+1

你說得很好。如果開銷與intrusive_ptr完全相同,它將取決於分配器。如果您不需要與弱計數關聯的額外單詞,則intrusive_ptr(或其他引用計數指針)可能會更小。 'std :: shared_ptr'功能非常全面,並且帶有與之相關的開銷。但是計算內存分配對開銷來說是一個很好的一階近似。 – 2012-02-01 03:03:41

2

intrusive_ptr不來與其他價格:你要搞亂你的內存管理信息實際設計中,你正在做的比需要的更復雜,投稿到您的項目不會是熟悉你的理由(甚至intrusive_ptr),你需要更多文檔。

另外:你有沒有基準測試複製智能指針的開銷實際上影響你的應用程序?我寧願先使用簡單版本,只在真正需要時纔會引入intrusive_ptr。

+0

我同意,額外的文檔和關於傳遞原始指針的模糊含義是缺點。 – 2011-04-19 18:28:58