共享指標(shared_ptr) 是現在的 boost 庫中提供的,並且應該是將來c++1x的標準庫中提供的乙個模板類。在此之前,iso/iec 14882:2003 標準庫 中的「自動指標 (auto_ptr)」也有類似的功能。顯然 shared_ptr 要比 auto_ptr 從功能上來說應該強大一些。這篇文章主要介紹 shared_ptr 的最基本用法和注意事項,相當於入門級多一點點。
shared_ptr 主要的功能是,管理動態建立的物件的銷毀。它的基本原理就是記錄物件被引用的次數,當引用次數為 0 的時候,也就是最後乙個指向某物件的共享指標析構的時候,共享指標的析構函式就把指向的記憶體區域釋放掉。
共享指標物件過載了 operator* 和 operator-> , 所以你可以像通常的指標一樣使用它。這部分不再贅述。
目前,visual c++ 2010 的 庫里,已經包含了 shared_ptr 模板類,也就是說,你可以直接這樣寫:
#include而 gnu g++ 的標準庫中還沒有支援(畢竟是將來的標準),如果在 g++ 中想使用 shared_ptr, 還是得用到 boost 庫,就是說,在 g++ 裡,你得這樣寫:
#include保險起見,你應該僅從以下幾種途徑構造乙個共享指標(以下例子中若沒特殊說明,t 就代表共享指標所指向的物件的型別):
也就是說,你可以直接定義乙個 shared_ptr 而不指定建構函式的內容:
shared_ptrptr;
這樣做的話,ptr 的意義就相當於乙個 null 指標。當你試圖在乙個空指標上做類似於 *ptr 或者 ptr->xx 之類的東西的時候,應該會收到異常的。
用**來表示,就是可以這樣使用:
shared_ptrptr(new t());
一種顯然的情況是這樣的:12
shared_ptrptr1(new t()); // 本行與 3.1. 中的構造方法是一樣的
shared_ptrptr2(ptr1); // 這就是使用複製建構函式的方法,會讓引用計數加 1
還有,shared_ptr 可以當作函式的引數傳遞,或者當作函式的返回值返回,這個時候其實也相當於使用複製建構函式。
shared_ptr 也可以型別轉換,有關型別轉換的詳情參見下面的 5. 此處假設 b 是 a 的子類,那麼,在 c 語言中 b 的指標當然是可以轉換成 a 的指標的。在共享指標裡,應該這樣做:12
shared_ptrptrb(new b());
shared_ptrptra( dynamic_pointer_cast(ptrb) );
shared_ptr 也可以直接賦值,但是必須是賦給相同型別的 shared_ptr 物件,而不能是普通的 c 指標或 new 運算子的返回值。當共享指標 a 被賦值成 b 的時候,如果 a 原來是 null, 那麼直接讓 a 等於 b 並且讓它們指向的東西的引用計數加 1; 如果 a 原來也指向某些東西的時候,如果 a 被賦值成 b, 那麼原來 a 指向的東西的引用計數被減 1, 而新指向的物件的引用計數加 1. 就是說以下**是允許的:12
3shared_ptra(new t());
shared_ptrb(new t());
a = b; // 此後 a 原先所指的物件會被銷毀,b 所指的物件引用計數加 1
shared_ptr 的物件在構造之後,可以被賦予空值,此時使用的應該是reset()函式,如: 1
2shared_ptra(new t());
a.reset(); // 此後 a 原先所指的物件會被銷毀,並且 a 會變成 null
當然理論上也可以這樣寫:12
shared_ptra(new t());
a = shared_ptr(); // 相當於給 a 賦乙個新構造的 shared_ptr, 也就是 null
shared_ptr 有兩種型別轉換的函式,乙個是 static_pointer_cast, 乙個是 dynamic_pointer_cast. 其實用法真的和 c++ 提供的 static_cast 和 dynamic_cast 很像,再結合 3.3. 的**和以下類似的**,幾乎沒什麼好講的:12
3shared_ptrptra;
shared_ptrptrb(new b());
ptra = dynamic_pointer_cast(ptrb);
很簡單,可以這樣用:12
shared_ptrptr(new t());
t *p = ptr.get(); // 獲得傳統 c 指標 1
2shared_ptrptr(new t());
ptr.reset(new t()); // 原來所指的物件會被銷毀
一定要注意,本節所述所有方法,都是錯誤的!
所謂在中途,指的就是不從 new 的返回值直接構造共享指標,比如從 this 指標構造自己的共享指標等。
其實這種和 8.1. 也是類似的,或者說,這種情況是 8.1. 的一種具體情況,比如,下面的**是錯誤的:12
3t *a = new t();
shared_ptrptr1(a);
shared_ptrptr2(a);
這樣的話,ptr1 和 ptr2 的引用計數是單獨算的,它們任意乙個物件在析構的時候,都會銷毀 a 所指的物件,所以,這個物件會被「銷毀兩次」。
有關執行效率的問題在這裡就不討論了。其它方面,shared_ptr 的構造要求比較高,如果物件在建立的時候沒有使用共享指標儲存的話,之後也不能用共享指標管理這個物件了。如果有引用迴圈 (reference cycle), 也就是物件 a 有指向物件 b 的共享指標,物件 b 也有指向物件 a 的共享指標,那麼它們都不會被析構。當然的,shared_ptr 也沒有辦法和garbage collecting比較,畢竟如果執行庫能夠干預,還是有演算法可以檢查到引用迴圈的。(例如求強連通分量的演算法。)
尤其,在類的成員函式的編寫的時候,有時我們經常希望得到「自己」的共享指標,但是這往往是無法得到的。此時也不能夠從 this 指標構造自己的共享指標(參見 8.1.),所以有時很憋悶。
實際上上面這麼多注意事項,中心思想就是乙個:讓 shared_ptr 正確地記錄物件被引用次數。如果能悟出一點 shared_ptr 的工作原理,基本上不會弄出太危險的事情來。
boost::shared_ptr的特點:
和前面介紹的boost::scoped_ptr相比,boost::shared_ptr可以共享物件的所有權,因此其使用範圍基本上沒有什麼限制(還是有一些需要遵循的使用規則,下文中介紹),自然也可以使用在stl的容器中。另外它還是執行緒安全的,這點在多執行緒程式中也非常重要。
boost::shared_ptr的使用規則:
boost::shared_ptr並不是絕對安全,下面幾條規則能使我們更加安全的使用boost::shared_ptr:
避免對shared_ptr所管理的物件的直接記憶體管理操作,以免造成該物件的重釋放
shared_ptr並不能對迴圈引用的物件記憶體自動管理(這點是其它各種引用計數管理記憶體方式的通病)。
不要構造乙個臨時的shared_ptr作為函式的引數。
如下列**則可能導致記憶體洩漏:
void test()
正確的用法為:
void test()
//當函式g()拋異常的時候就會洩露了,這個是boost文件上特地註明的標準bad practices,effective c++ third edition 條款17 有講到
c 智慧型指標 shared ptr
為了更容易更方便的使用動態記憶體,c 提供了兩種智慧型指標shared ptr和unique ptr來管理動態物件,智慧型指標負責自動釋放所管理的物件,避免因為不合適的釋放導致的記憶體洩露和訪問已釋放記憶體的bug 智慧型指標也是模板,建立乙個智慧型指標時,必須提供額外的型別資訊,如shared p...
C 智慧型指標 shared ptr
shared ptr 是乙個標準的共享所有權的智慧型指標,允許多個指標指向同乙個物件.定義在 memory 檔案中 非memory.h 命名空間為 std.shared ptr 是為了解決 auto ptr 在物件所有權上的侷限性 auto ptr 是獨佔的 在使用引用計數的機制上提供了可以共享所有...
C 智慧型指標之shared ptr
c 中用new來動態分配記憶體,delete手動釋放記憶體來達到動態管理記憶體的目的。因為保證在正確的時間釋放記憶體是非常困難的,忘記釋放記憶體就會產生記憶體洩露。為了更安全 便捷的使用動態記憶體,c 11標準庫提供了新的智慧型指標類來管理動態記憶體。智慧型指標在行為上和普通的指標是一樣的,只不過它...