閱讀目錄
正文
回到頂部
所謂資源就是,一旦用了它,將來必須還給系統。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的獨占性,這種語義被修改了。
auto_ptr
> p1(new
int(1)); /*1*/
auto_ptr
> p2(p1); /*2*/
auto_ptr
> p3;
p3= p2;/*3*/
p1 開始管理著值為1的物件,執行了2之後,p1被置空,由p2獨佔物件資源;執行3之後,p2被置為空,由p3獨佔物件資源。想象有乙個元素為auto_ptr的陣列:
auto_ptr
>vec[5]=
;for
(auto
& t : vec)
//vec[2]被置空
auto_ptr
> aptr = vec[2];
//程式執行奔潰
for(auto
& t : vec)
而我們的stl容器要求其元素可以有正常的複製行為,因此,stl容器容不得auto_ptr。而c++11新出現的智慧型指標unique_ptr比auto_ptr更聰明好用,unique_ptr拒絕直接的複製/賦值操作,必須通過reset/release介面來進行物件管理權的轉移,這無疑提高了安全性;unique_ptr的聰明還體現在:
unique_ptr
test
()unique_ptr
> p;
p = test();
在這裡test返回的臨時變數對p的賦值操作成功,因為臨時變數複製結束後就被銷毀,沒有機會通過臨時的unique_ptr物件去訪問無效資料,這種賦值是安全的。
總結一下:
auto_ptr不適用於stl容器,且易造成對無效指標的訪問導致程式奔潰。
unique_ptr比auto_ptr更加智慧型,安全性更高,應該選擇使用unique_ptr。
回到頂部
weak_ptr是一種不控制所指向物件生命期的智慧型指標,它指向由乙個shared_ptr管理的物件。講乙個weak_ptr繫結到乙個shared_ptr不會改變shared_ptr的引用計數,一旦最後乙個指向物件的shared_ptr被銷毀,物件就會被釋放,即使有weak_ptr指向物件,物件還是會被釋放。weak_ptr也取名自這種弱共享物件的特點。
相對於weak_ptr來說 ,shared_ptr是一種強引用的關係。在迴圈引用的情況下資源得不到**,將造成記憶體洩漏。如下圖出現了引用計數的迴圈引用問題:物件a被物件b所引用,物件c被物件a所引用,物件b被物件c所引用,這時每個物件的引用計數都是1,都在等待在引用它的物件釋放物件,造成一種迴圈等待的現象,而資源也不會被如願釋放掉。
weak_ptr弱引用的出現正是能夠打破這種迴圈引用。由於弱引用不更改引用計數,類似普通指標,只要把迴圈引用的一方使用弱引用,即可解除迴圈引用。雖然通過弱引用指標可以有效的解除迴圈引用,但這種方式必須在程式設計師能預見會出現迴圈引用的情況下才能使用,也可以是說這個僅僅是一種編譯期的解決方案,如果程式在執行過程中出現了迴圈引用,還是會造成記憶體洩漏的。因此,即使使用了智慧型指標,c++還是無法完全杜絕記憶體洩漏的問題。
智慧型指標分析
在我們寫 時,經常會忘記釋放掉動態開闢出來的記憶體,或者在我們的程式中,new和delete中間有如 throw goto return break 這樣引起執行流改變的語句時,就會造成沒有釋放資源,造成記憶體洩漏。void test1 t operator 注意函式返回值型別 上面說了智慧型指標是...
c 基礎 智慧型指標
設計原理 將基本型別指標封裝為類物件指標 這個類肯定是個模板,以適應不同基本型別的需求 並在析構函式裡編寫delete語句刪除指標指向的記憶體空間。auto ptr 則c 會把m example所指向的記憶體 使m example1 的值為null,所以在c 中,應絕對避免把auto ptr放到容器...
37 智慧型指標的分析
1 永恆的話題 這個程式的問題在於在 的27行,每for迴圈一次,就new乙個物件,但是只用乙個指標去指向這個物件,沒釋放記憶體,但是指標馬上又指向了另一段記憶體,這就造成了記憶體洩漏。2 深度的思考 3 智慧型指標分析 使用物件代替指標 從結果我們可以發現,指標指向的記憶體被釋放了,不會造成記憶體...