c++中智能指針的使用,個人總結

来源:https://www.cnblogs.com/wenxiang-wenxiang/archive/2022/06/25/16409990.html
-Advertisement-
Play Games

一、什麼是智能指針 一般來講C++中對於指針指向的對象需要使用new主動分配堆空間,在使用結束後還需要主動調用delete釋放這個堆空間。為了使得自動、異常安全的對象生存期管理可行,就出現了智能指針這個概念。簡單來看智能指針是 RAII(Resource Acquisition Is Initial ...


一、什麼是智能指針

  一般來講C++中對於指針指向的對象需要使用new主動分配堆空間,在使用結束後還需要主動調用delete釋放這個堆空間。為了使得自動、異常安全的對象生存期管理可行,就出現了智能指針這個概念。簡單來看智能指針是 RAII(Resource Acquisition Is Initialization,資源獲取即初始化) 機制對普通指針進行的一層封裝。這樣使得智能指針的行為動作像一個指針,本質上卻是一個對象,這樣可以方便管理一個對象的生命周期。

  智能指針作用總結:

  1. 處理記憶體泄漏。
  2. 處理空懸指針的問題。
  3. 處理異常造成的記憶體泄露。

  註:智能指針和原生指針不要混用,使用不當可能會導致程式異常;

二、智能指針有哪些

  智能指針(動態記憶體管理)頭文件 <memroy>

三、獨占式智能指針(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本身擁有的幾個主要方法
  1. get() 方法:獲取其保存的原生指針,儘量不要使用;
  2. release() 方法:釋放所管理指針的所有權,返回原生指針。但並不銷毀原生指針;
  3. reset() 方法:釋放並銷毀原生指針。如果參數為一個新指針,將管理這個新指針;
  4. 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擁有的幾個主要方法:
  1. get() 方法:獲取其保存的原生指針,儘量不要使用;
  2. bool() 方法:判斷是否擁有指針;
  3. reset() 方法:釋放並銷毀原生指針。如果參數為一個新指針,將管理這個新指針;
  4. unique() 方法:如果引用計數為 1(即對象所有權唯一),則返回 true,否則返回 false;
  5. 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擁有的幾個主要方法
  1. expired() 方法:判斷所指向的原生指針是否被釋放,如果被釋放了返回 true,否則返回 false;
  2. use_count() 方法:返回原生指針的引用計數;
  3. lock() 方法:返回 shared_ptr,如果原生指針沒有被釋放,則返回一個非空的 shared_ptr,否則返回一個空的 shared_ptr;
  4. 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

搜索

複製


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • TypeScript 是一種由微軟開發的自由和開源的編程語言,是一種非常受歡迎的 JavaScript 語言擴展,它也是 JavaScript 的一個超集,而且本質上向這個語言添加了可選的靜態類型和基於類的面向對象編程。它在現有的 JavaScript 語法之上加入了一層類型層,而這一層即使被刪除, ...
  • props傳遞數據 步驟: 首先,在子組件中聲明props選項 其次,在子組件中使用v-bind指令動態綁定屬性,通過插值表達式動態獲取數據 最後,在父組件的template中調用子組件標簽的使用傳遞數據 示例: 在子組件MovieItem.vue中 <template> <div class="s ...
  • 一、什麼是首屏載入 首屏時間(First Contentful Paint),指的是瀏覽器從響應用戶輸入網址地址,到首屏內容渲染完成的時間,此時整個網頁不一定要全部渲染完成,但需要展示當前視窗需要的內容,首屏載入可以說是用戶體驗中最重要的環節 二、載入慢的原因 在頁面渲染的過程,導致載入速度慢的因素 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 背景 等值查找,有數組、列表、HashMap等,已經足夠了,範圍查找,該用什麼數據結構呢?下麵介紹java中非常好用的兩個類TreeMap和ConcurrentSkipListMap。 TreeMap的實現基於紅黑樹 每一棵紅黑樹都是一顆二叉排序樹,又稱二叉查找樹(Binary Search Tre ...
  • 在大部分涉及到資料庫操作的項目裡面,事務控制、事務處理都是一個無法迴避的問題。得益於Spring框架的封裝,業務代碼中進行事務控制操作起來也很簡單,直接加個@Transactional註解即可,大大簡化了對業務代碼的侵入性。那麼對@Transactional事務註解瞭解的夠全面嗎?知道有哪些場景可能... ...
  • 寫在前面 這是我在接觸爬蟲後,寫的第二個爬蟲實例。 也是我在學習python後真正意義上寫的第二個小項目,第一個小項目就是第一個爬蟲了。 我從學習python到現在,也就三個星期不到,平時課程比較多,python是額外學習的,每天學習python的時間也就一個小時左右。 所以我目前對於python也 ...
  • 多對一關係是什麼 Django使用django.db.models.ForeignKey定義多對一關係。 ForeignKey需要一個位置參數:與該模型關聯的類 class Info(models.Model): user = models.ForeignKey(other_model,on_del ...
一周排行
    -Advertisement-
    Play Games
  • # 通過圖片流來返回圖片 # 前言 之前寫了個圖片介面,然後做了個授權,但是光返回圖片地址雖然能適應大部分需求,但是考慮到有些人不想去處理返回值,也是做了個直接返回圖片流的介面。 # 介面展示 ## 返回指定寬度和高度圖片流 ![image](https://img2023.cnblogs.com/ ...
  • System.Speech是.NET框架的一部分,提供了語音識別和語音合成的功能。通過使用System.Speech命名空間中的類,開發人員可以在.NET應用程式中實現語音識別功能。 在本文中,我將演示如何使用 System.Speech.NET,這是開發語音應用程式比較牛逼的內庫。它適用於 .NE ...
  • 導航屬性 導航屬性是作為.NET ORM核心功能中的核心,在SqlSugar沒有支持導航屬性前,都說只是一個高級DbHelper, 經過3年的SqlSugar重構已經擁有了一套 非常成熟的導航屬性體系,本文不是重點講SqlSugar而是重點講導航屬性的作用,讓更多寫Sql人還未使用ORM的人瞭解到O ...
  • SM2是國家密碼管理局於2010年12月17日發佈的橢圓曲線公鑰密碼演算法。 產生背景: 隨著密碼技術和電腦技術的發展,目前常用的1024位RSA演算法面臨嚴重的安全威脅,我們國家密碼管理部門經過研究,決定採用SM2橢圓曲線演算法替換RSA演算法。 SM2演算法和RSA演算法都是公鑰密碼演算法,SM2演算法是一種 ...
  • # 使用c#實現23種常見的設計模式 設計模式通常分為三個主要類別: - 創建型模式 - 結構型模式 - 行為型模式。 這些模式是用於解決常見的對象導向設計問題的最佳實踐。 以下是23種常見的設計模式並且提供`c#代碼案例`: ## 創建型模式: ### 1. 單例模式(Singleton) ``` ...
  • ## 一:背景 ### 1. 講故事 在這麼多的案例分析中,往往會發現一些案例是卡死線上程的內核態棧上,但拿過來的dump都是用戶態模式下,所以無法看到內核態棧,這就比較麻煩,需要讓朋友通過其他方式生成一個藍屏的dump,這裡我們簡單彙總下。 ## 二:如何生成內核態dump ### 1. 案例代碼 ...
  • 有時候,我們為了方便,我們往往使用擴展函數的代碼方式創建很多GridView的操作功能,如在隨筆《在DevExpress中使用BandedGridView表格實現多行表頭的處理》中介紹過多行表頭的創建及綁定處理,在《基於DevExpress的GridControl實現的一些界面處理功能》也介紹了一些... ...
  • # 1、背景 在我們開發的過程中有這麼一種場景, `/projectA` 目錄是 `hadoopdeploy`用戶創建的,他對這個目錄有`wrx`許可權,同時這個目錄屬於`supergroup`,在這個組中的用戶也具有這個目錄的`wrx`許可權,對於其他人,不可訪問這個目錄。現在有這麼一個特殊的用戶`r ...
  • 基於java的倉庫管理系統設計與實現,可適用於出庫、入庫、庫存管理,基於java的出入庫管理,java出入庫管理系統,基於java的WMS倉庫管理系統,庫存物品管理系統。 ...
  • 清醒點[toc] # Java虛擬線程 > 翻譯自 screencapture-pradeesh-kumar-medium-an-era-of-virtual-threads-java ```mermaid flowchart LR introduction-->a(why thread)-->b( ...