關於c++ 智能指針及 循環援用的問題。本站提示廣大學習愛好者:(關於c++ 智能指針及 循環援用的問題)文章只能為提供參考,不一定能成為您想要的結果。以下是關於c++ 智能指針及 循環援用的問題正文
c++智能指針引見
由於 C++ 言語沒有自動內存回收機制,順序員每次 new 出來的內存都要手動 delete,比方流程太復雜,最終招致沒有 delete,異常招致順序過遲到出,沒有執行 delete 的狀況並不稀有,並形成內存洩露。如此c++引入 智能指針 ,智能指針即是C++ RAII的一種使用,可用於靜態資源管理,資源即對象的管理戰略。 智能指針在 <memory>標頭文件的 std 命名空間中定義。 它們對 RAII 或 獲取資源即初始化 編程習用法至關重要。 RAII 的次要准繩是為一切堆分配資源提供一切權,例如靜態分配內存或零碎對象句柄、析構函數包括要刪除或釋放資源的代碼的堆棧分配對象,以及任何相關清算代碼。
c++智能指針類別
c++ 智能指針次要包括:unique_ptr,shared_ptr, weak_ptr, 這三種,其中auto_ptr 已被遺棄。
unique_ptr
只允許根底指針的一個一切者。 可以移到新一切者(具有挪動語義),但不會復制或共享(即我們無法失掉指向同一個對象的兩個unique_ptr)。 交換已棄用的 auto_ptr。 相較於 boost::scoped_ptr。 unique_ptr 玲珑高效;大小同等於一個指針,支持 rvalue 援用,從而可完成疾速拔出和對 STL 集合的檢索。 頭文件:<memory>。
運用unique_ptr,可以完成以下功用:
1、為靜態請求的內存提供異常平安。
2、將靜態請求內存的一切權傳遞給某個函數。
3、從某個函數前往靜態請求內存的一切權。
4、在容器中保管指針。
5、一切auto_ptr應該具有的(但無法在C++ 03中完成的)功用。
如下代碼所示:
class A; // 假如順序執行進程中拋出了異常,unique_ptr就會釋放它所指向的對象 // 傳統的new 則不行 unique_ptr<A> fun1() { unique_ptr p(new A); //do something return p; } void fun2() { // unique_ptr具有挪動語義 unique_ptr<A> p = f();// 運用挪動結構函數 // do something }// 在函數加入的時分,p以及它所指向的對象都被刪除釋放 shared_ptr
采用援用計數的智能指針。 shared_ptr基於“援用計數”模型完成,多個shared_ptr可指向同一個靜態對象,並維護了一個共享的援用計數器,記載了援用同一對象的shared_ptr實例的數量。當最後一個指向靜態對象的shared_ptr銷毀時,會自動銷毀其所指對象(經過delete操作符)。shared_ptr的默許才能是管理靜態內存,但支持自定義的Deleter以完成特性化的資源釋放舉措。頭文件:<memory>。
根本操作:shared_ptr的創立、拷貝、綁定對象的變卦(reset)、shared_ptr的銷毀(手動賦值為nullptr或分開作用域)、指定deleter等操作。
shared_ptr的創立,有兩種方式,
一,運用函數make_shared(會依據傳遞的參數調用靜態對象的結構函數);
二,運用結構函數(可從原生指針、unique_ptr、另一個shared_ptr創立)
shared_ptr<int> p1 = make_shared<int>(1);// 經過make_shared函數
shared_ptr<int> p2(new int(2));// 經過原生指針結構此外智能指針若為“空“,即不指向任何對象,則為false,否則為true,可作為條件判別。可以經過兩種方式指定deleter,一是結構shared_ptr時,二是運用reset辦法時。可以重載的operator->, operator *,以及其他輔佐操作如unique()、use_count(), get()等成員辦法。
weak_ptr
結合 shared_ptr 運用的特例智能指針。 weak_ptr 提供對一個或多個 shared_ptr 實例所屬對象的訪問,但是,不參與援用計數。 假如您想要察看對象但不需求其堅持活動形態,請運用該實例。 在某些狀況下需求斷開 shared_ptr 實例間的循環援用。 頭文件:<memory>。
weak_ptr的用法如下:
weak_ptr用於配合shared_ptr運用,並不影響靜態對象的生命周期,即其存在與否並不影響對象的援用計數器。weak_ptr並沒有重載operator->和operator *操作符,因而不可直接經過weak_ptr運用對象。提供了expired()與lock()成員函數,前者用於判別weak_ptr指向的對象能否已被銷毀,後者前往其所指對象的shared_ptr智能指針(對象銷毀時前往”空“shared_ptr)。循環援用的場景:如二叉樹中父節點與子節點的循環援用,容器與元素之間的循環援用等。
智能指針的循環援用
循環援用問題可以參考 這個鏈接 上的問題了解,“循環援用”復雜來說就是:兩個對象相互運用一個shared_ptr成員變量指向對方的會形成循環援用。招致援用計數生效。上面給段代碼來闡明循環援用:
#include <iostream> #include <memory> using namespace std; class B; class A { public:// 為了省去一些步驟這裡 數據成員也聲明為public //weak_ptr<B> pb; shared_ptr<B> pb; void doSomthing() { // if(pb.lock()) // { // // } } ~A() { cout << "kill A\n"; } }; class B { public: //weak_ptr<A> pa; shared_ptr<A> pa; ~B() { cout <<"kill B\n"; } }; int main(int argc, char** argv) { shared_ptr<A> sa(new A()); shared_ptr<B> sb(new B()); if(sa && sb) { sa->pb=sb; sb->pa=sa; } cout<<"sa use count:"<<sa.use_count()<<endl; return 0; }
下面的代碼運轉後果為:sa use count:2, 留意此時sa,sb都沒有釋放,發生了內存洩露問題!!!
即A外部有指向B,B外部有指向A,這樣關於A,B肯定是在A析構後B才析構,關於B,A肯定是在B析構後才析構A,這就是循環援用問題,違背慣例,招致內存洩露。
普通來講,解除這種循環援用有上面有三種可行的辦法( 參考 ):
1 . 當只剩下最後一個援用的時分需求手動打破循環援用釋放對象。
2 . 當A的生活期超越B的生活期的時分,B改為運用一個普通指針指向A。
3 . 運用弱援用的智能指針打破這種循環援用。
雖然這三種辦法都可行,但辦法1和辦法2都需求順序員手動控制,費事且容易出錯。我們普通運用第三種辦法:弱援用的智能指針weak_ptr。
強援用和弱援用
一個強援用當被援用的對象活著的話,這個援用也存在(就是說,當至多有一個強援用,那麼這個對象就不能被釋放)。share_ptr就是強援用。絕對而言,弱援用當援用的對象活著的時分不一定存在。僅僅是當它存在的時分的一個援用。弱援用並不修正該對象的援用計數,這意味這弱援用它並不對對象的內存停止管理,在功用上相似於普通指針,但是一個比擬大的區別是,弱援用能檢測到所管理的對象能否曾經被釋放,從而防止訪問合法內存。
運用weak_ptr來打破循環援用
代碼如下:
#include <iostream> #include <memory> using namespace std; class B; class A { public:// 為了省去一些步驟這裡 數據成員也聲明為public weak_ptr<B> pb; //shared_ptr<B> pb; void doSomthing() { if(pb.lock()) { } } ~A() { cout << "kill A\n"; } }; class B { public: //weak_ptr<A> pa; shared_ptr<A> pa; ~B() { cout <<"kill B\n"; } }; int main(int argc, char** argv) { shared_ptr<A> sa(new A()); shared_ptr<B> sb(new B()); if(sa && sb) { sa->pb=sb; sb->pa=sa; } cout<<"sb use count:"<<sb.use_count()<<endl; return 0; }
以上就是為大家帶來的關於c++ 智能指針及 循環援用的問題全部內容了,希望大家多多支持~