所謂資源就是,一旦用了它,未來必須還給系統。C++中內存資源的動態分配經由new與delete實現。問題在於,不管是有意無心,咱們有時候總會忘記釋放內存中的資源。例如delete語句出如今某個循環語句中,而咱們的continue或者break卻跳過了它的執行;或者是在程序中某個分支含有函數return語句,而delete操做放在return 語句以後;更加難以預料的事情是程序執行過程當中發生了異常,致使咱們的delete語句沒有執行。總的來講,把資源回收交給用戶並非一種好作法。咱們指望有一種機制,它幫助咱們管理從系統獲取而來的資源,當咱們再也不使用該資源時,該機制能自動幫咱們回收,避免了內存泄漏問題。智能指針就是這樣一種資源回收機制。程序員
《Effective C++》條款13提到,以對象來管理資源。這個條款提到了兩個觀點:數組
智能指針就是這樣的一種類。它們的行爲相似於指針,一樣支持解引用* 或取成員->運算。智能指針將基本內置類型指針封裝爲類對象指針,管理着該指針所指向的動態分配資源,並經過類的析構函數對資源進行釋放。在C++中,智能指針都是模板類,由於它們要管理的多是用戶自定義類型所分配的內存空間。安全
在STL中,一共是有四種智能指針:auto_ptr,unique_ptr,shared_ptr,weak_ptr。其中auto_ptr是C++98提供的智能指針,如今基本已經被棄用。緣由後面有說。
其中auto_ptr,unique_ptr是獨佔型的智能指針。這裏以auto_ptr爲例,在某個時刻下,只能有一個auto_ptr指向一個給定的對象。shared_ptr則容許多個指針指向同一個對象,而weak_ptr指向的是shared_ptr所管理的對象,它是一種弱引用。
shared_ptr的實現基於引用計數技術。智能指針管理的着一個對象,並記錄着全部管理同個對象的指針個數,這個個數稱爲計數。藉由智能指針去初始化或賦值其餘智能指針時,計數的值增長1,表示資源對象多了一個引用;當智能指針的生命週期結束或者指向別的對象時,計數的值減去1,表示資源對象減小一個引用。智能指針生命週期結束時,編譯器會調用它的析構函數,在析構函數中判斷引用計數的值是否爲0,若爲0,則釋放所管理的對象資源;若不爲0,代表還有其餘指針指向所管理的對象,不釋放該對象資源。函數
上面說到auto_ptr是C++98提供的智能指針,如今已經被摒棄,緣由在於爲了維護獨佔性,auto_ptr進行了不正常的複製/賦值行爲。
咱們的賦值操做在語義上保證了右操做數不會在賦值時受到修改,然而,爲了保證auto_ptr的獨佔性,這種語義被修改了。3d
auto_ptr<int> p1(new int(1)); /*1*/ auto_ptr<int> p2(p1); /*2*/ auto_ptr<int> p3; p3= p2;/*3*/
p1 開始管理着值爲1的對象,執行了2以後,p1被置空,由p2獨佔對象資源;執行3以後,p2被置爲空,由p3獨佔對象資源。想象有一個元素爲auto_ptr的數組:指針
auto_ptr<int>vec[5]= { auto_ptr<int>(new int(1)), auto_ptr<int>(new int(2)), auto_ptr<int>(new int(3)), auto_ptr<int>(new int(4)), auto_ptr<int>(new int(5)), }; for (auto & t : vec) { cout << *t << endl; } //vec[2]被置空 auto_ptr<int> aptr = vec[2]; //程序運行奔潰 for (auto & t : vec) { cout << *t << endl; }
而咱們的STL容器要求其元素能夠有正常的複製行爲,所以,STL容器容不得auto_ptr。而C++11新出現的智能指針unique_ptr比auto_ptr更聰明好用,unique_ptr拒絕直接的複製/賦值操做,必須經過reset/release接口來進行對象管理權的轉移,這無疑提升了安全性;unique_ptr的聰明還體如今:code
unique_ptr test() { unique_ptr <int> temp(new int (1)); return temp; } unique_ptr<int> p; p = test();
在這裏test返回的臨時變量對p的賦值操做成功,由於臨時變量複製結束後就被銷燬,沒有機會經過臨時的unique_ptr對象去訪問無效數據,這種賦值是安全的。
總結一下:對象
weak_ptr是一種不控制所指向對象生命期的智能指針,它指向由一個shared_ptr管理的對象。講一個weak_ptr綁定到一個shared_ptr不會改變shared_ptr的引用計數,一旦最後一個指向對象的shared_ptr被銷燬,對象就會被釋放,即便有weak_ptr指向對象,對象仍是會被釋放。weak_ptr也取名自這種弱共享對象的特色。blog
相對於weak_ptr來講 ,shared_ptr是一種強引用的關係。在循環引用的狀況下資源得不到回收,將形成內存泄漏。以下圖出現了引用計數的循環引用問題:對象A被對象B所引用,對象C被對象A所引用,對象B被對象C所引用,這時每一個對象的引用計數都是1,都在等待在引用它的對象釋放對象,形成一種循環等待的現象,而資源也不會被如願釋放掉。接口
weak_ptr弱引用的出現正是可以打破這種循環引用。因爲弱引用不更改引用計數,相似普通指針,只要把循環引用的一方使用弱引用,便可解除循環引用。雖然經過弱引用指針能夠有效的解除循環引用,但這種方式必須在程序員能預見會出現循環引用的狀況下才能使用,也能夠是說這個僅僅是一種編譯期的解決方案,若是程序在運行過程當中出現了循環引用,仍是會形成內存泄漏的。所以,即便使用了智能指針,C++仍是沒法徹底杜絕內存泄漏的問題。