程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 關於c++ 智能指針及 循環援用的問題

關於c++ 智能指針及 循環援用的問題

編輯:關於C++

關於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++ 智能指針及 循環援用的問題全部內容了,希望大家多多支持~

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved