詳解C 11智慧型指標

2021-10-07 00:09:54 字數 3866 閱讀 8631

目錄

詳解c++11智慧型指標 前言

c++11智慧型指標介紹

為什麼要使用智慧型指標

auto_ptr

unique_ptr

shared_ptr

weak_ptr

有些c++特性並沒有帶來實際上效能的提公升,而且還要花很多的時間來學習,導致我一段時間並不看好智慧型指標,因為普通指標用的很習慣了。但是看到越來越多的人在使用這個特性時,你沒有理由不去學習它,掌握它。

這篇博文來自:基本都是複製的,讀者也可以去看原文,我這裡把個人學習時認為重要的東西高亮,方便讀者快速獲取重要知識點。

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

智慧型指標主要用於管理在堆上分配的記憶體,它將普通的指標封裝為乙個棧物件。當棧物件的生存週期結束後,會在析構函式中釋放掉申請的記憶體,從而防止記憶體洩漏。c++ 11中最常用的智慧型指標型別為shared_ptr,它採用引用計數的方法,記錄當前記憶體資源被多少個智慧型指標引用。該引用計數的內存在堆上分配。當新增乙個時引用計數加1,當過期時引用計數減一。只有引用計數為0時,智慧型指標才會自動釋放引用的記憶體資源。

對shared_ptr進行初始化時不能將乙個普通指標直接賦值給智慧型指標,因為乙個是指標,乙個是類。可以通過make_shared函式或者通過建構函式傳入普通指標。並可以通過get函式獲得普通指標。

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

(c++98的方案,c++11已經拋棄)採用所有權模式。

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

auto_ptrp2;

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

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

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

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

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

unique_ptrp4; //#5

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

編譯器認為p4=p3非法,避免了p3不再指向有效資料的問題。嘗試複製p3時會編譯期出錯,而auto_ptr能通過編譯期從而在執行期埋下出錯的隱患。因此,unique_ptr比auto_ptr更安全。

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

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

unique_ptrpu2;

pu2 = pu1; // #1 不允許

unique_ptrpu3;

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

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

注:如果確實想執行類似與#1的操作,要安全的重用這種指標,可給它賦新值。c++有乙個標準庫函式std::move(),讓你能夠將乙個unique_ptr賦給另乙個。儘管轉移所有權後 還是有可能出現原有指標呼叫(呼叫就崩潰)的情況。但是這個語法能強調你是在轉移所有權,讓你清晰的知道自己在做什麼,從而不亂呼叫原有指標。

額外:boost庫的boost::scoped_ptr也是乙個獨占性智慧型指標,但是它不允許轉移所有權,從始而終都只對乙個資源負責,它更安全謹慎,但是應用的範圍也更狹窄。)

例如:

unique_ptrps1, ps2;

ps1 = demo("hello");

ps2 = move(ps1);

ps1 = demo("alexia");

cout << *ps2 << *ps1 << endl;

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_ptrsp(new int(1)); // sp 與 sp.get()是等價的。
share_ptr的簡單例子:

int main()

};class b

};void fun()

int main()

可以看到fun函式中pa ,pb之間互相引用,兩個資源的引用計數為2,當要跳出函式時,智慧型指標pa,pb析構時兩個資源引用計數會減1,但是兩者引用計數還是為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();

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...