最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++11智能指針核心體系詳解 (unique_ptr / shared_ptr / weak_ptr)

 更新時間:2026年06月04日 09:53:20   作者:handler01  
這段文章詳細探討了C++中裸指針的痛點及RAII思想,重點介紹了智能指針(如unique_ptr、shared_ptr)的概念與使用,強調(diào)了它們在資源管理上的的優(yōu)勢,如獨占所有權(quán)、共享引用計數(shù)、避免異常安全問題等

一、裸指針的痛點與 RAII 思想

1.1 裸指針與異常安全隱患

  • 概念解釋
    • 內(nèi)存泄漏 (Memory Leak):動態(tài)分配的堆內(nèi)存由于程序設(shè)計錯誤未被釋放,導(dǎo)致系統(tǒng)內(nèi)存持續(xù)消耗。
    • 異常安全 (Exception Safety):指當(dāng)程序在運行過程中拋出異常(Exception)時,程序依然能夠保持有效的內(nèi)部狀態(tài),并且不會發(fā)生資源(如內(nèi)存、鎖、文件句柄)泄漏的問題。
  • 筆記
    • 在傳統(tǒng) C++ 中,使用 new / delete 管理動態(tài)內(nèi)存極易引發(fā)異常安全問題。如果在兩者之間調(diào)用的函數(shù)拋出了異常,或者后續(xù)邏輯提前 return,控制流會直接跳轉(zhuǎn)跳過 delete,引發(fā)絕對的內(nèi)存泄漏。
    • 傳統(tǒng)方案的局限:使用 try-catch 攔截異常,釋放內(nèi)存后再將異常重新拋出。但在多處連續(xù)分配內(nèi)存的場景下,嵌套捕獲和釋放邏輯會導(dǎo)致代碼極度繁瑣和臃腫。
  • 代碼演示
void Func() {
    int* array1 = new int[10];
    int* array2 = new int[10]; // 若此處拋異常,array1 將永遠無法釋放
    try {
        // ... 可能拋出異常的業(yè)務(wù)邏輯 ...
    } catch(...) {
        // 發(fā)生異常時,必須手動清理已分配的所有內(nèi)存,再重新拋出
        delete[] array1;
        delete[] array2;
        throw; 
    }
    delete[] array1;
    delete[] array2;
}

1.2 RAII 設(shè)計理念與智能指針模擬

  • 概念解釋
    • RAII (Resource Acquisition Is Initialization):中文意為“資源獲取即初始化”。利用 C++ 局部對象生命周期(離開作用域自動調(diào)用析構(gòu)函數(shù))的特性,將動態(tài)資源強制綁定給局部對象,從而將資源管理的責(zé)任交給編譯器。
  • 筆記
    • 核心機制:在獲取資源時,將其委托給一個局部對象(構(gòu)造函數(shù)初始化)。當(dāng)對象離開作用域生命周期結(jié)束時,自動觸發(fā)析構(gòu)函數(shù)釋放資源。
    • 智能指針基本設(shè)計:除滿足 RAII 思路外,為了能像原生指針一樣使用,必須重載指針相關(guān)運算符(operator*、operator->、operator[])。

1.3 歷史遺留的坑點:auto_ptr(C++98)

  • 概念解釋
    • 所有權(quán)轉(zhuǎn)移 (Ownership Transfer):一種粗暴的資源交接方式,剝奪原指針的控制權(quán)交給新指針。
  • 筆記
    • 缺陷:拷貝時,將被拷貝對象的資源管理權(quán)強行轉(zhuǎn)移給拷貝對象,導(dǎo)致原指針懸空。若程序員不知情再次訪問原對象,程序?qū)⒅苯颖罎ⅰ?/li>
    • 結(jié)論:設(shè)計極其糟糕,C++11 之后已被廢棄,企業(yè)級項目中絕對禁止使用。

二、 現(xiàn)代 C++ 核心智能指針體系 (C++11/14)

2.1 獨占型智能指針:unique_ptr

  • 概念解釋
    • 獨占所有權(quán) (Exclusive Ownership):同一時刻只能有一個指針指向并擁有該對象,從語法層面徹底防止“二次釋放 (Double Free)”。
    • 核心函數(shù)std::make_unique (C++14)
  • 函數(shù)原型
template< class T, class... Args >
std::unique_ptr<T> make_unique( Args&&... args );

功能說明:完美轉(zhuǎn)發(fā)參數(shù)給 T 的構(gòu)造函數(shù)并在堆上創(chuàng)建對象,返回管理該對象的 unique_ptr。

  • 筆記
    • 核心語義:“這東西歸我,別人不準(zhǔn)碰”。
  • 特性
    • 禁止拷貝auto p2 = p1; 編譯直接攔截報錯。
    • 支持移動:可通過 auto p2 = std::move(p1); 將所有權(quán)轉(zhuǎn)移給 p2,轉(zhuǎn)移后 p1 變空。
    • 零性能開銷:無內(nèi)部狀態(tài)維護,運行效率等同原生裸指針。

2.2 共享型智能指針:shared_ptr

  • 概念解釋
    • 共享所有權(quán)與引用計數(shù) (Reference Counting):允許多個指針管理同一對象。底層維護一個原子計數(shù)器,記錄當(dāng)前管理者數(shù)量;僅當(dāng)計數(shù)器歸零時,才觸發(fā)真實對象的 delete。
  • 核心函數(shù)std::make_shared (C++11)
  • 函數(shù)原型
template< class T, class... Args >
std::shared_ptr<T> make_shared( Args&&... args );

功能說明:構(gòu)造對象并返回 shared_ptr。強烈推薦替代 new 使用,可實現(xiàn)內(nèi)存合并分配。

  • 筆記
    • shared_ptr 的核心是引用計數(shù)。因為一份資源可能被多個對象共享,所以必須保證這幾個對象看到的是同一個計數(shù)器。
    • 不能使用普通成員變量: 每個對象獨享,無法同步。
    • 不能使用靜態(tài)成員變量: 所有同類型的 shared_ptr 都會共享同一個計數(shù),哪怕它們管理的是不同的資源。
  • 正確做法: 在堆上動態(tài)開辟一個計數(shù)器(int* _pcount。構(gòu)造時伴隨資源 new 一個計數(shù)器;拷貝時所有對象指向同一個堆上的計數(shù)器,并對其 ++;析構(gòu)時對計數(shù)器 --

當(dāng)計數(shù)器減到 0 時,說明當(dāng)前是最后一個管理者,此時釋放資源和計數(shù)器。

2.3 伴生弱指針:weak_ptr與循環(huán)引用陷阱

  • 概念解釋:
    • 循環(huán)引用 (Circular Reference):復(fù)雜數(shù)據(jù)結(jié)構(gòu)(如雙向鏈表互相指)中,兩個 shared_ptr 互相持有對方,導(dǎo)致雙方引用計數(shù)形成閉環(huán),永遠無法降為 0,引發(fā)內(nèi)存泄漏。
    • 弱指針 (weak_ptr):專門為打破 shared_ptr 循環(huán)引用而生的伴生指針。它不具 RAII 特性,不增加引用計數(shù),僅作為資源的“觀察者”。
    • 核心函數(shù):std::weak_ptr::lock / std::weak_ptr::expired
  • 函數(shù)原型:
std::shared_ptr<T> lock() const noexcept;
bool expired() const noexcept;
  • 功能說明:expired() 檢查觀察的資源是否已釋放;lock() 用于在資源有效時,臨時提升返回一個強引用 shared_ptr 以安全訪問數(shù)據(jù)。
  • 筆記
    • 死鎖過程:雙向鏈表中節(jié)點 A 與 B 的 _next_prev 若為 shared_ptr,外部強引用釋放后,內(nèi)部互相依賴對方先析構(gòu),形成“回旋鏢死鎖”。
    • 破局之道:將雙向鏈表內(nèi)部指向類的指針改為 weak_ptr。
    • 訪問機制weak_ptr 沒有重載 *->,無法直接操作資源,必須通過 lock() 獲取 shared_ptr 保證線程與生命周期安全。

2.4 橫向?qū)Ρ扰c Reactor 模型選型規(guī)則

特性unique_ptrshared_ptr
所有權(quán)獨占 (Exclusive)共享 (Shared)
拷貝行為嚴格禁止允許(內(nèi)部引用計數(shù)+1)
開銷零(等同裸指針)存在(維護原子計數(shù)器)
適用場景唯一擁有者 (首選)必須在多處模塊共享同一個對象
  • Reactor 代碼選型邏輯
    • 最高規(guī)則:能用 unique_ptr 就別用 shared_ptr。
    • 獨占場景TcpServer 獨占 EpollerListener,必須采用 unique_ptr。
    • 共享場景Connection 既保存在 TcpServermap 中,又需要傳給其他工作線程/模塊,必須采用 shared_ptr。

三、 為什么必須擁抱make_*系列?

3.1 消除極度隱蔽的“異常安全”漏洞

  • 概念解釋
    • 函數(shù)參數(shù)求值順序未指定 (Unspecified Evaluation Order):C++17 前,編譯器對函數(shù)調(diào)用的多個參數(shù)執(zhí)行計算的順序是不確定的。
  • 筆記
    • new 的致命漏洞:如 Process(std::shared_ptr<Widget>(new Widget), ComputePriority());。編譯器可能先執(zhí)行 new Widget,然后執(zhí)行 ComputePriority()。如果此函數(shù)拋出異常,控制流中斷,未被智能指針接管的 Widget 將發(fā)生內(nèi)存泄漏。
    • make_* 的原子性:Process(std::make_shared<Widget>(), ComputePriority()); 將內(nèi)存分配與智能指針構(gòu)造綁定為不可分割的原子過程,完美堵死并發(fā)求值漏洞。

3.2 底層內(nèi)存布局與性能優(yōu)化 (make_shared專享)

  • 筆記
    • shared_ptr 底層不僅有對象,還有維護引用計數(shù)的控制塊 (Control Block)。
  • 傳統(tǒng)構(gòu)造std::shared_ptr<Widget> p(new Widget); 發(fā)生兩次堆內(nèi)存分配(一次對象,一次控制塊),增加系統(tǒng)開銷且導(dǎo)致內(nèi)存碎片化,CPU 緩存命中率低。
  • 合并分配make_shared 只進行單次合并內(nèi)存分配,開辟一塊連續(xù)大內(nèi)存同時存放對象和控制塊,零碎片且極大地優(yōu)化了 CPU Cache 表現(xiàn)。
  • 遵循 DRY 原則auto p = std::make_unique<Type>(); 避免了類型名稱手寫兩次的冗余。

3.3 架構(gòu)師視角:必須退回使用new的特例

  • 指定自定義刪除器 (Custom Deleter):make_* 寫死了 delete。當(dāng)管理 new[]、文件描述符 (FILE*)、網(wǎng)絡(luò) Socket 時,必須使用傳統(tǒng)智能指針構(gòu)造并傳入仿函數(shù)/Lambda 刪除器(注:C++ 標(biāo)準(zhǔn)庫已特化 unique_ptr<T[]>shared_ptr<T[]> 解決數(shù)組問題)。
  • 極大內(nèi)存與 weak_ptr 糾纏:因 make_shared 連續(xù)分配對象與控制塊,只要還有 weak_ptr 指向控制塊,哪怕強引用歸零觸發(fā)了對象析構(gòu),整塊極大的內(nèi)存也無法交還操作系統(tǒng),引發(fā)延遲釋放。此時必須分開 new。

到此這篇關(guān)于C++11智能指針核心體系詳解 (unique_ptr / shared_ptr / weak_ptr)的文章就介紹到這了,更多相關(guān)C++智能指針unique_ptr / shared_ptr / weak_ptr內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++鏈接器工作原理詳解

    C++鏈接器工作原理詳解

    當(dāng)文件見過編譯后就需要進行一個鏈接的操作接下來我們就說說什么是鏈接,本文給大家介紹了C++鏈接器是如何工作的,文章通過代碼示例和圖文介紹的非常詳細,需要的朋友可以參考下
    2024-02-02
  • C語言新建臨時文件和臨時文件名的方法

    C語言新建臨時文件和臨時文件名的方法

    這篇文章主要介紹了C語言新建臨時文件和臨時文件名的方法,分別是mkstemp()函數(shù)和mktemp()函數(shù)的使用,需要的朋友可以參考下
    2015-08-08
  • c/c++中struct定義、聲明、對齊方式解析

    c/c++中struct定義、聲明、對齊方式解析

    這篇文章通過C/C++的兩種聲明方式開始,給大家詳細分析了/c+中struct定義、聲明、對齊方式,對此有興趣的朋友可以參考學(xué)習(xí)下。
    2018-03-03
  • C語言中void類型指針的實現(xiàn)

    C語言中void類型指針的實現(xiàn)

    C語言中void類型指針有著特殊的用途,本文就來一下void類型指針的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-06-06
  • C++超詳細分析順序表

    C++超詳細分析順序表

    程序中經(jīng)常需要將一組數(shù)據(jù)元素作為整體管理和使用,需要創(chuàng)建這種元素組,用變量記錄它們,傳進傳出函數(shù)等。一組數(shù)據(jù)中包含的元素個數(shù)可能發(fā)生變化,順序表則是將元素順序地存放在一塊連續(xù)的存儲區(qū)里,元素間的順序關(guān)系由它們的存儲順序自然表示
    2022-03-03
  • c++利用stl set_difference對車輛進出區(qū)域進行判定

    c++利用stl set_difference對車輛進出區(qū)域進行判定

    這篇文章主要介紹了set_difference,用于求兩個集合的差集,結(jié)果集合中包含所有屬于第一個集合但不屬于第二個集合的元素,需要的朋友可以參考下
    2017-03-03
  • C++與Lua交互原理實例詳解

    C++與Lua交互原理實例詳解

    這篇文章主要介紹了C++與Lua交互原理實例詳解,有感興趣的同學(xué)可以研究下
    2021-02-02
  • C語言實現(xiàn)繪制南丁格爾玫瑰圖的示例代碼

    C語言實現(xiàn)繪制南丁格爾玫瑰圖的示例代碼

    玫瑰圖中有一種不等半徑的統(tǒng)計圖稱為南丁格爾玫瑰圖,網(wǎng)上很熱門,是一很有藝術(shù)感的漂亮的統(tǒng)計圖,下面我們就來看看如何使用C語言繪制它吧
    2024-03-03
  • QT實現(xiàn)簡單時鐘效果

    QT實現(xiàn)簡單時鐘效果

    這篇文章主要為大家詳細介紹了QT實現(xiàn)簡單時鐘效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • 利用C++實現(xiàn)從std::string類型到bool型的轉(zhuǎn)換

    利用C++實現(xiàn)從std::string類型到bool型的轉(zhuǎn)換

    利用C++實現(xiàn)從std::string類型到bool型的轉(zhuǎn)換。需要的朋友可以過來參考下。希望對大家有所幫助
    2013-10-10

最新評論

仁寿县| 来安县| 南平市| 胶南市| 仁布县| 龙里县| 利川市| 新沂市| 陵水| 鄂尔多斯市| 长泰县| 安图县| 肥乡县| 昌宁县| 信阳市| 靖宇县| 隆德县| 陆川县| 新巴尔虎左旗| 西丰县| 鸡泽县| 高要市| 吴桥县| 蓬安县| 定兴县| 怀集县| 通道| 诏安县| 怀来县| 荔浦县| 讷河市| 利津县| 彭州市| 汾西县| 临武县| 岗巴县| 墨江| 保德县| 常熟市| 永泰县| 墨竹工卡县|