Smart Pointers 智能指針
转载:http://boost.ez2learn.com/libs/smart_ptr/smart_ptr.htm
Introduction 簡介
Common Requirements 共同需求
Exception Safety 異常安全
Exception-specifications 異常規範
History and Acknowledgements 歷史和感謝
References 參考資料
Introduction 簡介
smart pointers(智能指針)是存儲“指向動態分配(在堆上)的對象的指針”的對象。他們的行為很像 C++ 的內建指針,只是它們可以在適當的時候自動刪除它們所指向的對象。智能指針在面對異常時有非常顯著的作用,它們可以確保動態分配對象的完全析構。它們還可以用於跟蹤多主人共享的動態分配對象。
在概念上,智能指針可以看作擁有它所指向的對象,並因此在對像不再需要時負責將它刪除。
智能指針庫提供五個(原文是五個,我數著怎麼是六個呢?暈——譯者注)智能指針類模板:
scoped_ptr | <boost/scoped_ptr.hpp> | 簡單的單一對象的唯一所有權。不可拷貝。 |
scoped_array | <boost/scoped_array.hpp> | 簡單的數組的唯一所有權。不可拷貝。 |
shared_ptr | <boost/shared_ptr.hpp> | 在多個指針間共享的對象所有權。 |
shared_array | <boost/shared_array.hpp> | 在多個指針間共享的數組所有權。 |
weak_ptr | <boost/weak_ptr.hpp> | 一個屬於 shared_ptr 的對象的無所有權的觀察者。 |
intrusive_ptr | <boost/intrusive_ptr.hpp> | 帶有一個侵入式引用計數的對象的共享所有權。 |
這些模板被設計用來補充 std::auto_ptr 模板的不足。
它們是在 Bjarne Stroustrup 的 "The C++ Programming Language" 第三版,14.4,資源管理部分描述的 "resource acquisition is initialization"(“獲得資源就是初始化”,《C++ 程序設計語言》中文版中譯為“資源申請即初始化”,個人認為不太確切——譯者注)慣用法的實例。
測試程序 smart_ptr_test.cpp,用來檢驗正確的操作。
網頁 compatibility(兼容性)結合 Boost 智能指針庫的老版本記述了智能指針實現的早期版本以來的一些變化。
網頁 smart pointer timings(智能指針測時)專注於那些犄角旮旯的性能問題。
網頁 smart pointer programming techniques(智能指針編程技術)列舉了shared_ptr
和 weak_ptr
的一些高級應用。
Common Requirements 共通需求
這些智能指針類模板有一個模板參數 T,它指定這個智能指針所指向的對象的類型。如果類型為 T 的對象的析構函數或operator delete 拋出異常,則智能指針模板的行為是未定義的。
在智能指針聲明的時候,T 可以是一個不完整的類型。除非另外指定,在智能指針實例化的時候,它要求 T 是一個完整的類型。實現體需要診斷出(視為錯誤)所有對這一需求的違例,包括不完整類型的缺失部分。參見checked_delete 函數模板的描述。
注意,shared_ptr 沒有這個限制,它的大部分成員函數都不要求 T 是一個完整的類型。
Rationale 基本原理
T 的需求是要小心謹慎地構造最大化的安全,而且還要允許 handle-body(也可叫做 pimpl(pimpl 全稱為 "pointer to implementation",可參考 Effective C++, 3rd Edition Item 25 29 和 31——譯者注))和其它類似慣用法。在這些慣用法中,一個智能指針可以出現在T 是一個不完整類型的編譯單元中。這樣就從實現中分離出接口,並對僅僅使用接口的編譯單元中隱藏實現。在特定智能指針文檔中記述的示例闡明了智能指針在這些慣用法中的應用。
注意,在析構的時候,scoped_ptr 要求 T 是一個完整類型,而 shared_ptr 並不要求。
Exception Safety 異常安全
這些智能指針類中的幾個函數被指定為在拋出異常時“沒有影響”或“除了如此這般之外沒有影響”。這就意味著當這些類中的某個對象拋出異常時,整個程序保持在那個引發異常的函數被調用之前的狀態。這等同於保證沒有可發覺的副作用。另一些函數從不拋出異常。那些拋出異常的函數能夠拋出的異常(假設T 符合共通需求)也僅限於std::bad_alloc,而且也僅限於那些在文檔中明確記述可能拋出 std::bad_alloc 的那些函數。
Exception-specifications 異常規範
沒有使用異常規範,參見 exception-specification rationale。
所有的智能指針模板都包含從不拋出異常的成員函數,因為他們不僅自己從不拋出異常,而且他們調用的其它函數也不會拋出異常。這樣的函數被標示為這樣的註釋:// never throws
。
摧毀所指向對象的類型的函數被共同需求禁止拋出異常。
History and Acknowledgements 歷史和感謝
2002 年 1 月。Peter Dimov 重寫了所有四個類,增加特性,修改 bug,而且將它們分開到四個單獨的頭文件中,並增加了 weak_ptr。關於這些更改的概要參見compatibility 網頁。
2001 年 5 月。Vladimir Prus 建議在析構時需要一個完整類型。討論了一些優雅的改進,包括 Dave Abrahams, Greg Colvin, Beman Dawes, Rainer Deyke, Peter Dimov, John Maddock, Vladimir Prus, Shankar Sai,還有其他人。
1999 年 11 月。Darin Adler 提供了 operator ==, operator !=, andstd::swap 和 std::less 的針對 shared 類型的特化。
1999 年 9 月。Luis Coelho 提供了 shared_ptr::swap 和 shared_array::swap。
1999 年 5 月。在 1999 年 4 月和 5 月,Valentin Bonnard 和 David Abrahams 提出大量建議而導致重大改進。
1998 年 10 月。Beman Dawes 提議復原 safe_ptr 和 counted_ptr 名字之下的原有語義,參加會議的有 Per Andersson, Matt Austern, Greg Colvin, Sean Corfield, Pete Becker, Nico Josuttis, Dietmar Kühl, Nathan Myers, Chichiang Wan 和 Judy Ward。經過討論,四個新的類名稱塵埃落定,並決定不需要嚴格遵循std::auto_ptr 的接口,並最終敲定了各個不同函數的標識和語義。
接下來的三個月中,shared_ptr 的幾個實現被提出來,並在 boost.org 郵件列表中進行討論。實現的爭論點始終圍繞著必須被堅持的引用計數,究竟是將它附加到所指向的對象上,還是分離到別處。這些不同本身又各自包含兩種較大的變化:
- 直接分離:shared_ptr 包含一個指向對象的指針和一個指向數量的指針。
- 間接分離:shared_ptr 包含一個指向輔助對象的指針,那個對象再依次包含一個指向對像和數量的指針。
- 嵌入式附加:數量是所指向對象的一個成員。
- 放置式附加:數量的附加經由 operator new 進行控制。
每一種實現技術都有優勢和劣勢。我們測量了直接和間接方法的不同的運行時間,發現至少在 Intel Pentium 芯片上只有極微小的差別。Kevlin Henney 提供了一篇他寫的論文 "Counted Body Techniques"。Dietmar Kühl 提出一個允許用戶選擇他們更喜歡的實現的優雅的模板偏特化技術,並進行了實驗。
但是 Greg Colvin 和 Jerry Schwarz 認為“參數化會阻礙用戶”,而最終我們選擇僅僅提供直接的實現。
1994 年夏天。Greg Colvin 向 C++ 標準委員會提議名為 auto_ptr 和 counted_ptr 的類,它們和我們現在所說的scoped_ptr 和 shared_ptr 非常相似。[Col-94] 在極少的幾次全體委員會沒有接受庫工作組的建議的案例之一中,counted_ptr 被否決了,並出人意外地將所有權轉讓語義加入到auto_ptr 中。
References 參考資料
[Col-94] Gregory Colvin, Exception Safe Smart Pointers, C++ committee document 94-168/N0555, July, 1994.
[E&D-94] John R. Ellis & David L. Detlefs, Safe, Efficient Garbage Collection for C++, Usenix Proceedings, February, 1994. This paper includes an extensive discussion of weak pointers and an extensive bibliography.