C 11智慧型指標

2021-10-02 14:50:28 字數 4775 閱讀 7980

為什麼要使用智慧型指標:

智慧型指標的作用是管理乙個指標,因為存在以下這種情況:申請的空間在函式結束時忘記釋放,造成記憶體洩漏。使用智慧型指標可以很大程度上的避免這個問題,因為智慧型指標就是乙個類,當超出了類的作用域是,類會自動呼叫析構函式,析構函式會自動釋放資源。所以智慧型指標的作用原理就是在函式結束時自動釋放記憶體空間,不需要手動釋放記憶體空間。

採用所有權模式

auto_ptr< string> p1 (new string ("i reigned lonely as a cloud.」));

auto_ptrp2;

p2 = p1; //auto_ptr不會報錯.

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

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

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

unique_ptrp3 (new string ("auto"));   //#4

unique_ptrp4; //#5

p4 = p3;//此時會報錯!!

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

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

unique_ptrpu1(new string ("hello world"));

unique_ptrpu2;

pu2 = pu1; // #1 not allowed

unique_ptrpu3;

pu3 = unique_ptr(new string ("you")); // #2 allowed

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

unique_ptrps1(new string ("hello world"));

unique_ptrps2;

ps2 = move(ps1);

ps1 = unique_ptr(new string ("you"));

cout << *ps2 <可以對同乙個指標p進行託管,通過乙個託管計數n來統計,當n為0時即最後乙個shared_ptr 物件接觸託管時,p指標會自動呼叫delete和析構函式。只有動態分配的物件指標才能交給shared_ptr 物件託管,普通遍歷、全域性變數的指標不可託管,因為無析構函式。託管時第二個shared_ptr 物件必須通過已經託管的shared_ptr 物件進行託管同一指標。

要確保用 new 動態分配的記憶體空間在程式的各條執行路徑都能被釋放是一件麻煩的事情。c++ 11 模板庫的 標頭檔案中定義的智慧型指標,即 shared _ptr 模板,就是用來部分解決這個問題的。

只要將 new 運算子返回的指標 p 交給乙個 shared_ptr 物件「託管」,就不必擔心在**寫delete p語句——實際上根本不需要編寫這條語句,託管 p 的 shared_ptr 物件在消亡時會自動執行delete p。而且,該 shared_ptr 物件能像指標 p —樣使用,即假設託管 p 的 shared_ptr 物件叫作 ptr,那麼 *ptr 就是 p 指向的物件。

通過 shared_ptr 的建構函式,可以讓 shared_ptr 物件託管乙個 new 運算子返回的指標,寫法如下:

shared_ptrptr(new t); // t 可以是 int、char、類等各種型別

此後,ptr 就可以像 t* 型別的指標一樣使用,即 *ptr 就是用 new 動態分配的那個物件。

多個 shared_ptr 物件可以共同託管乙個指標 p,當所有曾經託管 p 的 shared_ptr 物件都解除了對其的託管時,就會執行delete p

#include #include using namespace std;

class a

; ~a()

};int main()

程式的輸出結果如下:

2,2,223

2 destructed

end5 destructed

4 destructed

3 destructed

可以用第 14 行及第 16 行的形式讓多個 shareclptr 物件託管同乙個指標。這多個 shared_ptr 物件會共享乙個對共同託管的指標的「託管計數」。有 n 個 shared_ptr 物件託管同乙個指標 p,則 p 的託管計數就是 n。當乙個指標的託管計數減為 0 時,該指標會被釋放。shared_ptr 物件消亡或託管了新的指標,都會導致其原託管指標的託管計數減 1。

第 20、21 行,shared_ptr 的 reset 成員函式可以使得物件解除對原託管指標的託管(如果有的話),並託管新的指標。原指標的託管計數會減 1。

輸出的第 4 行說明,用 new 建立的動態物件 a(2) 被釋放了。程式中沒有寫 delete 語句,而 a(2) 被釋放,是因為程式的第 23 行執行後,已經沒有 shared_ptr 物件託管 a(2),於是 a(2) 的託管計數變為 0。最後乙個解除對 a(2) 託管的 shared_ptr 物件會釋放 a(2)。

main 函式結束時,sp1、sp2、sp3 物件消亡,各自將其託管的指標的託管計數減為 0,並且釋放其託管的指標,於是會有以下輸出:

5 destructed

4 destructed

3 destructed

只有指向動態分配的物件的指標才能交給 shared_ptr 物件託管。將指向普通區域性變數、全域性變數的指標交給 shared_ptr 託管,編譯時不會有問題,但程式執行時會出錯,因為不能析構乙個並沒有指向動態分配的記憶體空間的指標。

注意,不能用下面的方式使得兩個 shared_ptr 物件託管同乙個指標(第二個shared_ptr 物件必須通過已經託管的shared_ptr 物件進行託管同一指標):

a* p = new a(10);

shared_ptr sp1(p), sp2(p);

sp1 和 sp2 並不會共享同乙個對 p 的託管計數,而是各自將對 p 的託管計數都記為 1(sp2 無法知道 p 已經被 sp1 託管過)。這樣,當 sp1 消亡時要析構 p,sp2 消亡時要再次析構 p,這會導致程式崩潰。

用來解決shared_ptr相互引用導致死鎖weak_ptr不可以直接訪問物件,必須用過lock()函式賦值給乙個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。

class b;

class a

};class b

};void fun()

{shared_ptrpb(new b());

shared_ptrpa(new a());

pb->pa_ = pa;

pa->pb_ = pb;

cout《可以看到fun函式中pa ,pb之間互相引用,兩個資源的引用計數為2,當要跳出函式時,智慧型指標pa,pb析構時兩個資源引用計數會減一,但是兩者引用計數還是為1,導致跳出函式時資源沒有被釋放(a b的析構函式沒有被呼叫),如果把其中乙個改為weak_ptr就可以了,我們把類a裡面的shared_ptr pb_; 改為weak_ptr pb_; 執行結果如下,這樣的話,資源b的引用開始就只有1,當pb析構時,b的計數變為0,b得到釋放,b釋放的同時也會使a的計數減一,同時pa析構時使a的計數減一,那麼a的計數為0,a得到釋放。

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

C 11智慧型指標

本文介紹c 的四種智慧型指標,其中後三種是c 11新增加的,auto ptr已被棄用。要編譯c 11,需要安裝g 4.8 sudo add apt repository ppa ubuntu toolchain r test sudo apt get update sudo apt get inst...

c 11 智慧型指標

如果在程式中使用new從堆 自由儲存區 分配記憶體,等到不需要時,應使用delete將其釋放。c 引入了智慧型指標auto ptr,以幫助自動完成這個過程。c 11摒棄了auto ptr,並新增了三種智慧型指標 unique ptr,shared ptr,weak ptr。一.auto ptr,un...

c 11 智慧型指標

首先來看shared ptr,先貼一小部分vs2013裡的實現 template class shared ptr template class shared ptr public ptr base ty template explicit shared ptr ux px template cla...