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
  • Github / Gitee QQ群(1群) : 813100564 / QQ群(2群) : 579033769 視頻教學 介紹 MiniWord .NET Word模板引擎,藉由Word模板和數據簡單、快速生成文件。 Getting Started 安裝 nuget link : https:// ...
  • Array.Sort Array類中相當實用的我認為是Sort方法,相比起冗長的冒泡排序,它的出現讓排序更加的簡化 結果如下: 還可以聲明一個靜態方法用來專門調用指定數組排序,從名為 array 的一維數組中 a 索引處開始,到 b 元素 從小到大排序。 註意: a + b 不能大於 array 的 ...
  • 前言 在上一篇文章CLR類型系統概述里提到,當運行時掛起時, 垃圾回收會執行堆棧遍歷器(stack walker)去拿到堆棧上值類型的大小和堆棧根。這裡我們來翻譯BotR里一篇專門介紹Stackwalking的文章,希望能加深理解。 順便說一句,StackWalker在中文里似乎還沒有統一的翻譯,J ...
  • 使用過 nginx 的小伙伴應該都知道,這個中間件是可以設置跨域的,作為今天的主角,同樣的 反向代理中間件的 YARP 毫無意外也支持了跨域請求設置。 有些小伙伴可能會問了,怎樣才算是跨域呢? 在 HTML 中,一些標簽,例如 img、a 等,還有我們非常熟悉的 Ajax,都是可以指向非本站的資源的 ...
  • 什麼是Git Git 是一個開源的分散式版本控制系統,用於敏捷高效地處理任何或小或大的項目。 Git 是 Linus Torvalds 為了幫助管理 Linux 內核開發而開發的一個開放源碼的版本控制軟體。 Git 與常用的版本控制工具 CVS, Subversion 等不同,它採用了分散式版本庫的 ...
  • 首先CR3是什麼,CR3是一個寄存器,該寄存器內保存有頁目錄表物理地址(PDBR地址),其實CR3內部存放的就是頁目錄表的記憶體基地址,運用CR3切換可實現對特定進程記憶體地址的強制讀寫操作,此類讀寫屬於有痕讀寫,多數驅動保護都會將這個地址改為無效,此時CR3讀寫就失效了,當然如果能找到CR3的正確地址... ...
  • 說明 onlyoffice為一款開源的office線上編輯組件,提供word/excel/ppt編輯保存操作 以下操作均基於centos8系統,officeonly鏡像版本7.1.2.23 鏡像下載地址:https://yunpan.360.cn/surl_y87CKKcPdY4 (提取碼:1f92 ...
  • 二叉樹查找指定的節點 前序查找的思路 1.先判斷當前節點的no是否等於要查找的 2.如果是相等,則返回當前節點 3.如果不等,則判斷當前節點的左子節點是否為空,如果不為空,則遞歸前序查找 4.如果左遞歸前序查找,找到節點,則返回,否繼續判斷,當前的節點的右子節點是否為空,如果不為空,則繼續向右遞歸前 ...
  • ##Invalid bound statement (not found)出現原因和解決方法 ###前言: 想必各位小伙伴在碼路上經常會碰到奇奇怪怪的事情,比如出現Invalid bound statement (not found),那今天我就來分析以下出現此問題的原因。 其實出現這個問題實質就是 ...
  • ###一、背景知識 爬蟲的本質就是一個socket客戶端與服務端的通信過程,如果我們有多個url待爬取,只用一個線程且採用串列的方式執行,那隻能等待爬取一個結束後才能繼續下一個,效率會非常低。 需要強調的是:對於單線程下串列N個任務,並不完全等同於低效,如果這N個任務都是純計算的任務,那麼該線程對c ...