[6] 智能指針boost::weak_ptr

【1】boost::weak_ptr簡介html

boost::weak_ptr屬於boost庫,定義在namespace boost中,包含頭文件 #include<boost/weak_ptr.hpp>即可以使用。ios

【2】boost::weak_ptr詳解程序員

智能指針boost::scope_ptr和智能指針boost::shared_ptr就徹底能夠解決全部單個對象內存的管理問題。函數

這兒咋還多出一個boost::weak_ptr,是否還有某些案例咱們沒有考慮到呢? 學習

回答:有。首先 boost::weak_ptr是專門爲boost::shared_ptr而準備的。 spa

有時候,咱們只關心可否使用對象,並不關心內部的引用計數。 指針

boost::weak_ptr是 boost::shared_ptr的觀察者(Observer)對象,觀察者?觀察者怎麼理解呢? code

觀察者意味着boost::weak_ptr只對boost::shared_ptr進行引用,而不改變其引用計數。 server

當被觀察的boost::shared_ptr失效後,相應的boost::weak_ptr也隨之失效。 htm

那麼,爲何須要這個觀察者呢?那還得從循環引用談起。

引用計數是一種便利的內存管理機制,但它有一個很大的缺點,那就是不能管理循環引用的對象。

示例代碼以下:

 1 #include <iostream>
 2 #include <boost/shared_ptr.hpp>
 3 #include <boost/weak_ptr.hpp>
 4 
 5 class parent;  6 class children;  7 
 8 typedef boost::shared_ptr<parent> parent_ptr;  9 typedef boost::shared_ptr<children> children_ptr; 10 
11 class parent 12 { 13 public: 14     ~parent() { std::cout <<"destroying parent\n"; } 15 
16 public: 17  children_ptr children; 18 }; 19 
20 class children 21 { 22 public: 23     ~children() { std::cout <<"destroying children\n"; } 24 
25 public: 26  parent_ptr parent; 27 }; 28 
29 
30 void test() 31 { 32     parent_ptr father(new parent()); 33     children_ptr son(new children); 34 
35     father->children = son; 36     son->parent = father; 37 } 38 
39 void main() 40 { 41     std::cout<<"begin test...\n"; 42  test(); 43     std::cout<<"end test.\n"; 44 }

運行該程序能夠看到:即便退出了test函數後,因爲parent和children對象互相引用,它們的引用計數都是1,不能自動釋放,而且此時這兩個對象再沒法訪問到。

這也就引發了C++中那臭名昭著的內存泄漏。

<1> 通常來說,解除這種循環引用有下面有三種可行的方法:

1. 當只剩下最後一個引用的時候須要手動打破循環引用釋放對象。

2. 當parent的生存期超過children的生存期的時候,children改成使用一個普通指針指向parent。

3. 使用弱引用的智能指針打破這種循環引用。

雖然這三種方法均可行,但方法1和方法2都須要程序員手動控制,麻煩且容易出錯。

下面主要介紹一下第三種方法和boost中的弱引用的智能指針boost::weak_ptr。 

<2> 什麼是強引用和弱引用?

一個強引用是指當被引用的對象仍活着的話,這個引用也存在(也就是說,只要至少有一個強引用,那麼這個對象就不會也不能被釋放)。boost::share_ptr就是強引用。

相對而言,弱引用當引用的對象活着的時候不必定存在。僅僅是當它自身存在的時的一個引用。

弱引用並不修改該對象的引用計數,這意味這弱引用它並不對對象的內存進行管理。

在功能上相似於普通指針,然而一個比較大的區別是,弱引用能檢測到所管理的對象是否已經被釋放,從而避免訪問非法內存。

boost::weak_ptr boost::weak_ptr<T>是boost提供的一個弱引用的智能指針,它的聲明能夠簡化以下:

 1 namespace boost  2 {  3 template<typename T> class weak_ptr  4 {  5 public:  6     template <typename Y>
 7     weak_ptr(const shared_ptr<Y>& r);  8 
 9     weak_ptr(const weak_ptr& r); 10     
11     ~weak_ptr(); 12 
13     T* get() const; 14     bool expired() const; 15     shared_ptr<T> lock() const; 16 }; 17 }

能夠看到,boost::weak_ptr必須從一個boost::share_ptr或另外一個boost::weak_ptr轉換而來,這也說明,進行該對象的內存管理的是那個強引用的boost::share_ptr。

boost::weak_ptr只是提供了對管理對象的一個訪問手段。

boost::weak_ptr除了對所管理對象的基本訪問功能(經過get()函數)外,還有兩個經常使用的功能函數:

1. expired() 用於檢測所管理的對象是否已經釋放;

2. lock() 用於獲取所管理的對象的強引用指針。

<3> 經過boost::weak_ptr來打破循環引用

因爲弱引用不更改引用計數,相似普通指針,只要把循環引用的一方使用弱引用,便可解除循環引用。

對於上面的那個例子來講,只要把children的定義改成以下方式,便可解除循環引用:

1 class children 2 { 3 public: 4     ~children() { std::cout <<"destroying children\n"; } 5 
6 public: 7     boost::weak_ptr<parent> parent; 8 };

【3】boost::weak_ptr總結

雖然經過弱引用指針能夠有效的解除循環引用,但這種方式必須在程序員能預見會出現循環引用的狀況下才能使用,也能夠是說這個僅僅是一種編譯期的解決方案。

若是程序在運行過程當中出現了循環引用,仍是會形成內存泄漏的。

所以,不要認爲只要使用了智能指針便能杜絕內存泄漏。

畢竟,對於C++來講,因爲沒有垃圾回收機制,內存泄漏對每個程序員來講都是一個很是頭痛的問題。 

 

聲明:爲了便於個人理解和學習,文章有部分修改內容,原文轉自《 智能指針--weak_ptr 》,(我學習的大師哦~)

 

Good Good Study, Day Day Up.

順序  選擇  循環  總結

相關文章
相關標籤/搜索