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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...