在動態內存管理過程,要注意釋放動態內存的正確時間,若是不釋放的話,會形成內存泄露;可是釋放時若還有指針引用內存的話,會產生引用非法內存的指針。而智能指針就是爲了解決這一難點而誕生的,就如它的名字同樣,若是你使用智能指針的話,它就會智能的在合適的時機釋放掉內存。智能指針包括shared_ptr,unique_ptr和weak_ptr.安全
shared_ptr和unique_ptr支持的操做;函數
shared_ptr<T>sp; //T爲參數類型,默認爲空指針 unique_ptr<T>up; *p;//解引用 p->get();//返回智能指針保存的指針 swap(p,q);//交換p和q種的指針 //構造一個shared_ptr make_shared<T>(arg);//返回一個shared_ptr對象,並用arg來初始化它 shared_ptr<T>p(q);//用q來初始化p p.use_count();//返回p種的計數。
咱們能夠認爲每一個智能指針都有綁定一個計數器,一般稱其爲引用計數。不管咱們什麼時候拷貝一個智能指針,計數器都會遞增,例如指針
①用一個shared_ptr初始化另外一個shared_ptrcode
shared_ptr<T>p(q);//q中的計數器會加一
②將智能指針做爲參數傳遞對象
int func(std::shared_ptr<int>p){ return p->use_count(); } int mian(){ std::shared_ptr<int>p = std::make_shared<int>(10); std::cout<<func(p);//輸出的結果爲2 }
③做爲參數的返回值:內存
shared_ptr<T> func();
shared_ptr的構造函數時explict修飾的,所以咱們不能將一個指針隱式轉換爲智能指針。作用域
shared_ptr<int>p = new int(10);//錯誤,不能將內置指針轉換爲智能指針 shared_ptr<int>p(new int(10));//ok
另外shared_ptr還支持reset操做來改變智能指針綁定的指針。get
p.reset();//p取消與指針的綁定,變成默認的nullptr; p.reset(new int(20));//p與新的匿名地址綁定。
unique_ptr與shared_ptr不一樣的是,它不可以拷貝,也就是說它的計數器是能小於等於1.當unique_ptr被銷燬的時候,它指向的對象也將被銷燬。內存管理
unique不支持拷貝和賦值:io
std::unique_ptr<int>p(new int(10));//ok,直接初始化。 std::unique_ptr<int>q(p);//錯誤,不能拷貝 q = p;//錯誤,不能賦值
unique支持reset和release操做:
reset的操做和shared_ptr的reset操做相同,release操做會返回當前智能指針保存的對象並將智能指針置爲空。經過這兩個操做能夠進行unique_ptr指向對象的專業。
p.reset(q.release());//將q保存的對象轉移給p。
shared_ptr和unique_ptr默認爲用delete刪除對象,也能夠自定義刪除器
shared_ptr的自動刪除器定義以下:
假設如今有class 爲connection,刪除函數爲disconnect(connection *con);那麼自動刪除定義刪除器爲:
std::shared_ptr<connection>p(new connection(),disconnect); //第二個參數爲自定義的刪除器函數。
unique_ptr的自動刪除器要在參數列表指明刪除器的函數指針類型,這裏用decltype函數自動推導。
std::unique_ptr<connection,decltype(disconnect)*>p (new connection(10),disconnect);
weak_ptr是一種不控制對象生長週期的智能指針,它指向一個shared_ptr指向的對象,將weak_ptr綁定到一個shared_ptr保存的對象上,也不會增長shared_ptr的計數器。一旦最後一個指向對象的shared_ptr被銷燬,對象將被釋放,即便還有weak_ptr綁定這個對象。
std::shared_ptr<int>p(new int(10)); std::weak_ptr<int>wp(p);//wp若共享p,p的引用計數不會改變
因爲對象不存在,因此不能用wp直接訪問對象,而是用成員函數lock來檢查指向的對象是否存在,lock就返回一個指向的shared_ptr.與其它shared_ptr不一樣,只要此shared_ptr存在,它的底層對象就一直存在。
if(shared_ptr<int>np = wp.lock())//只有np不爲空時才能進入if { //在if中使用共享對象np是安全的,np和p共享對象。 }
class B; class A{ public: A(){ std::cout<<"A construction"<<std::endl; } ~A(){ std::cout<<"A destruction"<<std::endl; } std::shared_ptr<B>pb; }; class B{ public: B(){ std::cout<<"B construction"<<std::endl; } ~B(){ std::cout<<"B destruction"<<std::endl; } std::shared_ptr<A>pa; }; int main(){ std::shared_ptr<A>a(new A()); std::shared_ptr<B>b(new B()); a->pb = b; b->pa = a; }
上面的代碼的輸出是什麼呢?
A construction B construction
沒錯,能夠很顯然的看到A和B在主函數結束後並無被銷燬,由於A和B互相持有對方的引用計數,二者的引用計數都不會較小到0,所以內存也不會被釋放。
而將代碼修改到以下後:
class B; class A{ public: A(){ std::cout<<"A construction"<<std::endl; } ~A(){ std::cout<<"A destruction"<<std::endl; } std::weak_ptr<B>pb; }; class B{ public: B(){ std::cout<<"B construction"<<std::endl; } ~B(){ std::cout<<"B destruction"<<std::endl; } std::weak_ptr<A>pa; }; int main(){ std::shared_ptr<A>a(new A()); std::shared_ptr<B>b(new B()); a->pb = b; b->pa = a; }
輸入爲
A construction B construction B destruction A destruction
前面咱們說過weak_ptr時弱共享,不會增長shared_ptr的計數引用,所以A和B只有自己一個計數引用,當自身離開做用域後,計數器歸0,釋放內存。