一、什么是智能指標
一般來講C++中對于指標指向的物件需要使用new主動分配堆空間,在使用結束后還需要主動呼叫delete釋放這個堆空間,為了使得自動、例外安全的物件生存期管理可行,就出現了智能指標這個概念,簡單來看智能指標是 RAII(Resource Acquisition Is Initialization,資源獲取即初始化) 機制對普通指標進行的一層封裝,這樣使得智能指標的行為動作像一個指標,本質上卻是一個物件,這樣可以方便管理一個物件的生命周期,
智能指標作用總結:
- 處理記憶體泄漏,
- 處理空懸指標的問題,
- 處理例外造成的記憶體泄露,
注:智能指標和原生指標不要混用,使用不當可能會導致程式例外;
二、智能指標有哪些
智能指標(動態記憶體管理)頭檔案 <memroy>
- std::unique_ptr:擁有獨有物件所有權語意的智能指標(cplusplus,C++參考手冊)
- std::shared_ptr:擁有共享物件所有權語意的智能指標(cplusplus,C++參考手冊)
- std::week_ptr:到 std::shared_ptr 所管理物件的弱參考(cplusplus,C++參考手冊)
- std::auto_ptr(C++11起棄用):擁有嚴格物件所有權語意的智能指標(cplusplus,C++參考手冊)
三、獨占式智能指標(std::unique_ptr)
1 class SmartPointer 2 { 3 public: 4 SmartPointer() 5 { 6 cout << "SmartPointer::SmartPointer()" << endl; 7 } 8 ~SmartPointer() 9 { 10 11 cout << "SmartPointer::~SmartPointer()" << endl; 12 } 13 };
- 獨占式:
- unique_ptr擁有所指向(管理)的資源、物件的所有權,即不能被其他unique_ptr所指;
- unique_ptr不能進行賦值或拷貝操作;
unique_ptr<SmartPointer> ptest1(new SmartPointer("空格")); // unique_ptr<SmartPointer> ptest2 = ptest1; //此時編譯報錯
- 但可以使用std::move或者relase()方法將源unique_ptr 指標指向資源所有權轉向新unique_ptr;
unique_ptr<SmartPointer> ptest1(new SmartPointer("空格")); cout << "ptest1 location: " << ptest1.get() << endl; unique_ptr<SmartPointer> ptest2 = move(ptest1); //將ptest1指向物件所有權轉移給ptest2,ptest1置空為NULL cout << "ptest2 location: " << ptest2.get() << endl; unique_ptr<SmartPointer> ptest3(ptest2.release()); //將ptest2指向物件所有權轉移給ptest3,ptest2置空為NULL cout << "ptest3 location: " << ptest2.get() << endl;
結果為:

unique_ptr本身擁有的幾個主要方法:
- get() 方法:獲取其保存的原生指標,盡量不要使用;
- release() 方法:釋放所管理指標的所有權,回傳原生指標,但并不銷毀原生指標;
- reset() 方法:釋放并銷毀原生指標,如果引數為一個新指標,將管理這個新指標;
- bool() 方法:判斷是否擁有指標;
unique_ptr<SmartPointer> ptest1(new SmartPointer()); ptest1.reset(new SmartPointer()); //釋放銷毀原有物件,持有新物件 ptest1.reset(); //直接釋放銷毀原物件 ptest1 = nullptr; //同上
四、共享式智能指標(std::shared_ptr)
- 共享式
共享權,多個shared_ptr同時擁有一個原生指標(記憶體)的所有權,最后一個擁有者負責原生指標的釋放和銷毀;
std::shared_ptr<SmartPointer> pTest1(new SmartPointer()); std::shared_ptr<SmartPointer> pTest2 = pTest1; //編譯正常,允許所有權的共享 cout << "pTest1 location: " << pTest1.get() << endl; cout << "pTest2 location: " << pTest2.get() << endl; shared_ptr<SmartPointer> pTest3 = make_shared<SmartPointer>();//新建共享指標方法,make_shared效果類似new pTest2 = pTest3; cout << "pTest3 location: " << pTest3.get() << endl; cout << "pTest2 location: " << pTest2.get() << endl;
結果:

- 計數器
共享指標類中包括一個成員函式用來記住所管理的記憶體當前有多少個指標指向它;
use_count()方法可以獲取指向物件的shared_ptr個數;
shared_ptr<string> pStr_1(new string("霜之哀傷")); shared_ptr<string> pStr_2 = make_shared<string>("火之高興"); auto pStr_3 = pStr_1; //此時指向“霜之哀傷”數量為2,“火之高興”為1; cout << *pStr_1 << " : " << pStr_1.use_count() << "\t" << *pStr_2 << " : " << pStr_2.use_count() << endl; pStr_3 = pStr_2; //此時指向“霜之哀傷”數量為1,“火之高興”為2; cout << *pStr_1 << " : " << pStr_1.use_count() << "\t" << *pStr_2 << " : " << pStr_2.use_count() << endl;
結果:

- shared_ptr擁有的幾個主要方法:
- get() 方法:獲取其保存的原生指標,盡量不要使用;
- bool() 方法:判斷是否擁有指標;
- reset() 方法:釋放并銷毀原生指標,如果引數為一個新指標,將管理這個新指標;
- unique() 方法:如果參考計數為 1(即物件所有權唯一),則回傳 true,否則回傳 false;
- use_count() 方法:回傳參考計數的大小;
shared_ptr<SmartPointer> pTest1(new SmartPointer()); cout << pTest1.unique() << endl; //此時為true; shared_ptr<SmartPointer> pTest2 = pTest1; cout << pTest1.unique() << endl; //此時為false pTest1.reset(new SmartPointer()); //釋放銷毀原有物件,持有新物件 pTest1.reset(); //直接釋放銷毀原物件 pTest1 = nullptr; //同上
結果:

五、輔助指標/弱指標(std::weak_ptr)
class B; class A { public: A() { cout << "A::A()" << endl; } ~A() { cout << "A::~A()" << endl; } shared_ptr<B> pB; }; class B { public: B() { cout << "B::B()" << endl; } ~B() { cout << "B::~B()" << endl; } shared_ptr<A> pA; };
weak_ptr是為了輔助shared_ptr所引入的弱參考智能指標,主要是為了解決shared_ptr中回圈參考(物件A持有物件B,物件B持有物件A,此時兩個物件的參考計數均為2;在跳出作用范圍時,兩個物件參考計數均減1但還有1,導致跳出作用范圍后兩個物件的資源沒有釋放銷毀,產生記憶體泄漏)的問題,
shared_ptr<A> pA(new A()); //新建A類物件 shared_ptr<B> pB(new B()); //新建B類物件 pA->pB = pB; //A類中持有B類 pB->pA = pA; //B類中持有A類 //此時構成了回圈參考 cout << pA.use_count() << endl; cout << pB.use_count() << endl;
結果:
回圈參考在跳出作用范圍時未呼叫類A與類B解構式,導致記憶體泄漏,此時可以將類內的shared_ptr改為weak_ptr可以避免;

weak_ptr不能直接使用原生指標構造,可以使用一個shared_ptr和另一個weak_ptr進行構造;
weak_ptr擁有的幾個主要方法
- expired() 方法:判斷所指向的原生指標是否被釋放,如果被釋放了回傳 true,否則回傳 false;
- use_count() 方法:回傳原生指標的參考計數;
- lock() 方法:回傳 shared_ptr,如果原生指標沒有被釋放,則回傳一個非空的 shared_ptr,否則回傳一個空的 shared_ptr;
- reset() 方法:將本身置空;
shared_ptr<A> pA(new A()); weak_ptr<A> weak_pA = pA; //弱指標,不增加參考計數 cout << "A參考計數:" << weak_pA.use_count() << endl; shared_ptr<A> pA_1 = weak_pA.lock(); //此時又一個shared_ptr指向原生指標,計數加1 cout << "A參考計數:" << weak_pA.use_count() << endl; cout << weak_pA.expired() << endl; //銷毀原生指標 pA.reset(); pA_1.reset(); cout << weak_pA.expired() << endl; weak_pA.reset(); //置空weak_ptr
結果:

參考:
https://www.cnblogs.com/corineru/p/10895249.html
https://www.cnblogs.com/TenosDoIt/p/3456704.html
https://zhuanlan.zhihu.com/p/436290273
https://www.csdn.net/tags/MtTaEg0sMTkwMTctYmxvZwO0O0OO0O0O.html
搜索
復制
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/497678.html
標籤:C++
