c 之 智慧型指標

2021-10-07 12:32:16 字數 4299 閱讀 5860

在c++記憶體中,除了靜態記憶體和棧之外,每個程式還有乙個記憶體池,這部分記憶體被稱為自由空間或者堆。程式用堆來儲存動態分配的物件即那些在程式執行時分配的物件,當動態物件不再使用時,我們的**必須顯式的銷毀它們。

在c++中,動態記憶體的管理是用一對運算子完成的:new和delete,new:在動態記憶體中為物件分配一塊空間並返回乙個指向該物件的指標,delete:指向乙個動態獨享的指標,銷毀物件,並釋放與之關聯的記憶體。

動態記憶體管理經常會出現兩種問題:一種是忘記釋放記憶體,會造成記憶體洩漏;一種是尚有指標引用記憶體的情況下就釋放了它,就會產生引用非法記憶體的指標。

為了更加容易(更加安全)的使用動態記憶體,引入了智慧型指標的概念。智慧型指標的行為類似常規指標,重要的區別是它負責自動釋放所指向的物件。標準庫提供的兩種智慧型指標的區別在於管理底層指標的方法不同,shared_ptr允許多個指標指向同乙個物件,unique_ptr則「獨佔」所指向的物件。標準庫還定義了一種名為weak_ptr的伴隨類,它是一種弱引用,指向shared_ptr所管理的物件,這三種智慧型指標都定義在memory標頭檔案中。

c++裡面的四個智慧型指標: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中後三個是c++11支援,並且第乙個已經被11棄用。

採用所有權模式。

auto_ptr< string> p1 (

new string ("i reigned lonely as a cloud.」));

auto_ptr p2;

p2 = p1;

//auto_ptr不會報錯.

此時不會報錯,p2剝奪了p1的所有權,但是當程式執行時訪問p1將會報錯。所以auto_ptr的缺點是:存在潛在的記憶體崩潰問題!

unique_ptr實現獨佔式擁有或嚴格擁有概念,保證同一時間內只有乙個智慧型指標可以指向該物件。它對於避免資源洩露(例如「以new建立物件後因為發生異常而忘記呼叫delete」)特別有用。

採用所有權模式,還是上面那個例子

unique_ptr p3 (

new string (

"auto"))

;//#4

unique_ptr p4; //#5

p4 = p3;

//此時會報錯!!

編譯器認為p4=p3非法,避免了p3不再指向有效資料的問題。因此,unique_ptr比auto_ptr更安全。

另外unique_ptr還有更聰明的地方:當程式試圖將乙個 unique_ptr 賦值給另乙個時,如果源 unique_ptr 是個臨時右值,編譯器允許這麼做;如果源 unique_ptr 將存在一段時間,編譯器將禁止這麼做,比如:

unique_ptr

pu1(

new string (

"hello world"))

;unique_ptr pu2;

pu2 = pu1;

// #1 not allowed

unique_ptr pu3;

pu3 = unique_ptr

(new string (

"you"))

;// #2 allowed

其中#1留下懸掛的unique_ptr(pu1),這可能導致危害。而#2不會留下懸掛的unique_ptr,因為它呼叫 unique_ptr 的建構函式,該建構函式建立的臨時物件在其所有權讓給 pu3 後就會被銷毀。這種隨情況而已的行為表明,unique_ptr 優於允許兩種賦值的auto_ptr 。

shared_ptr實現共享式擁有概念。多個智慧型指標可以指向相同物件,該物件和其相關資源會在「最後乙個引用被銷毀」時候釋放。從名字share就可以看出了資源可以被多個指標共享,它使用計數機制來表明資源被幾個指標共享。可以通過成員函式use_count()來檢視資源的所有者個數。除了可以通過new來構造,還可以通過傳入auto_ptr, unique_ptr,weak_ptr來構造。當我們呼叫release()時,當前指標會釋放資源所有權,計數減一。當計數等於0時,資源會被釋放。

shared_ptr 是為了解決 auto_ptr 在物件所有權上的侷限性(auto_ptr 是獨佔的), 在使用引用計數的機制上提供了可以共享所有權的智慧型指標。

成員函式:

use_count

() 返回引用計數的個數

unique

() 返回是否是獨佔所有權( use_count 為 1

)swap

() 交換兩個 shared_ptr 物件(即交換所擁有的物件)

reset

() 放棄內部物件的所有權或擁有物件的變更, 會引起原有物件的引用計數的減少

get(

) 返回內部物件(指標)

, 由於已經過載了(

)方法, 因此和直接使用物件是一樣的.如 shared_ptr<

int>sp(

newint(1

)); sp 與 sp.

get(

)是等價的

share_ptr雖然已經很好用了,但是有一點share_ptr智慧型指標還是有記憶體洩露的情況,當兩個物件相互使用乙個shared_ptr成員變數指向對方,會造成迴圈引用,使引用計數失效,從而導致記憶體洩漏。

weak_ptr 是一種不控制物件生命週期的智慧型指標, 它指向乙個 shared_ptr 管理的物件. 進行該物件的記憶體管理的是那個強引用的shared_ptr, weak_ptr只是提供了對管理物件的乙個訪問手段。weak_ptr 設計的目的是為配合 shared_ptr 而引入的一種智慧型指標來協助 shared_ptr 工作, 它只可以從乙個 shared_ptr 或另乙個 weak_ptr 物件構造, 它的構造和析構不會引起引用記數的增加或減少。weak_ptr是用來解決shared_ptr相互引用時的死鎖問題,如果說兩個shared_ptr相互引用,那麼這兩個指標的引用計數永遠不可能下降為0,資源永遠不會釋放。它是對物件的一種弱引用,不會增加物件的引用計數,和shared_ptr之間可以相互轉化,shared_ptr可以直接賦值給它,它可以通過呼叫lock函式來獲得shared_ptr

classb;

//宣告

classa}

;classb}

;void

fun(

)int

main()

可以看到fun函式中pa ,pb之間互相引用,兩個資源的引用計數為2,當要跳出函式時,智慧型指標pa,pb析構時兩個資源引用計數會減一,但是兩者引用計數還是為1,導致跳出函式時資源沒有被釋放(a b的析構函式沒有被呼叫)執行結果沒有輸出析構函式的內容,造成記憶體洩露

如果把其中乙個改為weak_ptr就可以了,我們把類a裡面的shared_ptr pb_,改為weak_ptr pb_ ,執行結果如下:

111

2b delete

a delete

這樣的話,資源b的引用開始就只有1,當pb析構時,b的計數變為0,b得到釋放,b釋放的同時也會使a的計數減1,同時pa析構時使a的計數減1,那麼a的計數為0,a得到釋放。

注意:我們不能通過weak_ptr直接訪問物件的方法,比如b物件中有乙個方法print(),我們不能這樣訪問,pa->pb_->print(),因為pb_是乙個weak_ptr,應該先把它轉化為shared_ptr,如:

shared_ptrp = pa-

>pb_.

lock()

;p->

print()

;

weak_ptr 沒有過載*和->但可以使用 lock 獲得乙個可用的 shared_ptr 物件. 注意, weak_ptr 在使用前需要檢查合法性.

expired

() 用於檢測所管理的物件是否已經釋放, 如果已經釋放, 返回 true

; 否則返回 false

.lock

() 用於獲取所管理的物件的強引用(shared_ptr)

. 如果 expired 為 true

, 返回乙個空的 shared_ptr; 否則返回乙個 shared_ptr, 其內部物件指向與 weak_ptr 相同.

use_count

() 返回與 shared_ptr 共享的物件的引用計數.

reset

() 將 weak_ptr 置空.

weak_ptr

() 支援拷貝或賦值, 但不會影響對應的 shared_ptr 內部物件的計數.

參考

C 之智慧型指標

本文發表於1999年10月份的c c users journal,17 10 1.為什麼稱它為 自動 指標?auto ptr只是眾多可能的智慧型指標之一。許多商業庫提供了更複雜的智慧型指標,用途廣泛而令人驚異,從管理引用的數量到提供先進的 服務。可以把標準c auto ptr看作智慧型指標的ford...

C 之智慧型指標

c 中有四個智慧型指標 auto ptr,shared ptr,weak ptr,unique ptr,其中後三個是c 11支援,並且第乙個已經被c 11棄用。智慧型指標從書面意思來說,就是智慧型。主要是動態記憶體的使用很容易出問題,要在正確的時間正確釋放記憶體是很困難的。有時我們可能忘了釋放記憶體...

c 之智慧型指標

設計出乙個class像指標,但是功能更強大,分為兩種形式一種是標準庫的源 早期的指標,多半是過載 和 第二種是迭代器的智慧型指標 1.早期的智慧型指標 templateclass shared ptr t operator const shared ptr t p px p private t px...