爲了解決C++內存泄漏的問題,C++11引入了智能指針(Smart Pointer)。ios
智能指針的原理是,接受一個申請好的內存地址,構造一個保存在棧上的智能指針對象,C++中有一個重要原則,在函數結束時(不管是正常返回,仍是由於異常除法的對戰回退),會將全部棧對象銷燬,也就是會調用全部棧對象的析構函數。智能指針內部保存的內存也就被釋放掉了(除非將智能指針保存起來)。數組
C++11提供了三種智能指針:std::shared_ptr, std::unique_ptr, std::weak_ptr,使用時需添加頭文件<memory>。安全
shared_ptr使用引用計數,每個shared_ptr的拷貝都指向相同的內存。每使用他一次,內部的引用計數加1,每析構一次,內部的引用計數減1,減爲0時,刪除所指向的堆內存。shared_ptr內部的引用計數是安全的,可是對象的讀取須要加鎖。函數
(1)初始化this
能夠經過構造函數、std::make_shared<T>輔助函數和reset方法來初始化shared_ptrspa
#include "stdio.h" #include<memory> #include<iostream> using namespace std; void main() { shared_ptr<int> p1(new int(10)); cout << "p1的引用計數:"<<p1.use_count() << endl; shared_ptr<int> p2 = p1; cout << "p1的引用計數:" << p1.use_count() << " p2的引用計數:" << p2.use_count() << endl; p2.reset(new int(2)); // 當智能指針中有值時,調用rest會使引用計數減1 cout << "p1的引用計數:" << p1.use_count() << " p2的引用計數:" << p2.use_count() << endl; cout << *p2 << endl; p2.reset(); cout << "p1的引用計數:" << p1.use_count() << " p2的引用計數:" << p2.use_count() << endl; shared_ptr<int> p3 = make_shared<int>(20); shared_ptr<int> p4; p4.reset(new int(30)); cout << "p4的引用計數:" << p4.use_count() << endl; }
注意:不能將一個原始指針直接賦值給一個智能指針指針
std::shared_ptr<int> p4 = new int(1);// error
reset()包含兩個操做。當智能指針中有值的時候,調用reset()會使引用計數減1.當調用reset(new xxx())從新賦值時,智能指針首先是生成新對象,而後將就對象的引用計數減1(固然,若是發現引用計數爲0時,則析構舊對象),而後將新對象的指針交給智能指針保管。rest
(2)獲取原始指針code
std::shared_ptr<int> p4(new int(5)); int *pInt = p4.get();
(3)指定刪除器對象
智能指針能夠指定刪除器,當智能指針的引用計數爲0時,自動調用指定的刪除器來釋放內存。std::shared_ptr能夠指定刪除器的一個緣由是其默認刪除器不支持數組對象,這一點須要注意。
template<class T, class D> shared_ptr(T *p, D d)
void DeleteIntPtr(int *p) { delete p; } shared_ptr<int> p(new int(1), DeleteIntPtr);
當咱們使用shared_ptr管理動態數組時,須要指定刪除器,由於std::shared_ptr的默認刪除器不支持數組對象
shared_ptr<int> p(new int[10], [](int *p){delete[] p;});
也可使用syd::default_delete做爲刪除器,default_delete的內部是經過調用delete來實現的
shared_ptr<int> p(new int[10], deault_delete<int[]>);
(4)注意make_share和make_arrar_share的使用
(5)使用shared_ptr注意事項
a. 不要用一個原始指針初始化初始化多個shared_ptr
b. 不要在函數實參中建立shared_ptr
unique_ptr是一個獨佔型的智能指針,它不容許其它的智能指針共享其內部的指針,不容許經過賦值將一個unique_ptr賦值給另一個unique_ptr,unique_ptr不容許複製,但能夠經過函數返回給其它的unique_ptr,還能夠經過move來轉移到其它的unique_ptr,這樣它自己就再擁有原來指針的全部權。
注意:unique_ptr不支持make_share
弱引用指針week_ptr是用來監視shared_ptr的,不會使引用計數加1,它無論理shared_ptr內部的指針,week_ptr沒有重載操做符,不共享指針,不操做資源。weak_ptr指針能夠用來返回this指針和解決循環引用的問題
(1)use_count獲取當前觀測資源的引用計數
shared_ptr<int> p(new int(1)); weak_ptr<int> p1(p); cout << p1.use_count() <<endl;
(2)經過expired()來判斷觀測的資源是否已經被釋放
(3)經過lock()來獲取監視的shared_ptr
(4)weak_ptr返回this指針
不能直接將this指針返回爲shared_ptr,須要經過派生std::enable_shared_from_this類,並經過其方法shared_from_this來返回智能指針,緣由是enable_shared_from_this類中有一個weak_ptr指針,這個weak_ptr用來觀測this智能指針,調用shared_from_this,會調用內部的weak_ptr的lock()方法
(5 )weak_ptr解決循環引用的問題
#include "stdio.h" #include<memory> #include<iostream> using namespace std; class B; class A { public: shared_ptr<B> bptr; ~A() { cout << "A is delete!" << endl; } }; class B { public: shared_ptr<A> aptr; ~B() { cout << "B is delete!" << endl; } }; void main() { { shared_ptr<A> a(new A()); shared_ptr<B> b(new B()); a->bptr = b; b->aptr = a; cout << "A的引用計數:" << a.use_count() << endl; cout << "B的引用計數:" << b.use_count() << endl; } int i = 0; }
離開做用域後引用計數減1,不會去刪除指針,致使內存泄漏
經過weak_ptr解決該問題,只要將A或B中的任意一個成員改爲weak_ptr便可