c++弱指針實現原理

在 C++ 中,弱指針(std::weak_ptr)是一種特殊的智能指針,其核心目標是?解決?std::shared_ptr?的循環引用問題?,同時不增加對象的引用計數。它的實現原理基于與?std::shared_ptr?共享的 ?控制塊(Control Block)?,并通過 ?弱引用計數(Weak Reference Count)? 管理資源生命周期。

?1. 弱指針的設計目標?

  • ?打破循環引用?:當兩個?std::shared_ptr?互相引用時,引用計數無法歸零,導致內存泄漏。std::weak_ptr?不增加引用計數,允許安全觀測對象是否存在。
  • ?臨時訪問資源?:通過?lock()?方法臨時獲取?std::shared_ptr,確保訪問時對象存活。

?2. 核心實現原理?

?(1) 控制塊(Control Block)?
  • ?數據結構?:
    每個由?std::shared_ptr?管理的對象會關聯一個 ?控制塊?,包含以下信息:

    • ?強引用計數(Strong Ref Count)?:當前?std::shared_ptr?的引用數量。
    • ?弱引用計數(Weak Ref Count)?:當前?std::weak_ptr?的引用數量。
    • ?對象指針?(若強引用計數 > 0,否則為?nullptr)。
    • ?刪除器(Deleter)? 和 ?分配器(Allocator)?(可選)。
  • ?生命周期?:

    • 當 ?強引用計數歸零? 時,對象被銷毀(調用析構函數并釋放內存)。
    • 當 ?弱引用計數歸零? 時,控制塊自身被釋放。
?(2)?std::weak_ptr?的構造?
  • ?從?std::shared_ptr?構造?:

std::shared_ptr<int> sp = std::make_shared<int>(42);
std::weak_ptr<int> wp(sp);  // 不增加強引用計數,但增加弱引用計數
    • wp?共享?sp?的控制塊,弱引用計數 +1。
  • ?從另一個?std::weak_ptr?構造?:

std::weak_ptr<int> wp2(wp);  // 弱引用計數 +1
    (3)?std::weak_ptr?的使用?
    • ?lock()?方法?:
      嘗試將?std::weak_ptr?提升為?std::shared_ptr

    if (auto sp = wp.lock()) {  // 若對象存活,強引用計數 +1// 安全使用 sp
    }
    
      • 若對象已銷毀(強引用計數為 0),返回空的?std::shared_ptr
    • ?expired()?方法?:
      快速檢查對象是否存活(無需創建?std::shared_ptr):

    if (!wp.expired()) {  // 檢查強引用計數是否 > 0// 對象存活
    }
    

    ?3. 內部實現細節?

    ?(1) 控制塊的內存管理?
    • ?std::shared_ptr?構造時?:
      若首次創建?std::shared_ptr,動態分配控制塊,強引用計數初始化為 1,弱引用計數初始化為 1(因為?std::shared_ptr?自身也持有一個弱引用)。

    • ?std::weak_ptr?構造時?:
      弱引用計數 +1,但不影響強引用計數。

    • ?std::shared_ptr?析構時?:
      強引用計數 -1。若強引用計數歸零:

      1. 銷毀對象(調用析構函數并釋放內存)。
      2. ?若弱引用計數也為 0?,釋放控制塊;否則保留控制塊供?std::weak_ptr?查詢。
    • ?std::weak_ptr?析構時?:
      弱引用計數 -1。若弱引用計數歸零且強引用計數已為 0,釋放控制塊。

    ?(2) 線程安全性?
    • ?引用計數的原子操作?:
      控制塊的引用計數(強/弱)通過原子操作(如?std::atomic)實現線程安全。

    ?4. 示例:解決循環引用

    #include <memory>
    class Node {
    public:std::shared_ptr<Node> next;std::weak_ptr<Node> prev;  // 使用 weak_ptr 打破循環引用
    };int main() {auto node1 = std::make_shared<Node>();auto node2 = std::make_shared<Node>();node1->next = node2;      // node2 強引用計數 = 2node2->prev = node1;      // node1 弱引用計數 = 1// node1 和 node2 的強引用計數最終可歸零,正確釋放內存
    }
    

    ?5. 性能與限制?

    • ?性能開銷?:

      • std::weak_ptr?的創建、銷毀和?lock()?涉及原子操作,略慢于裸指針。
      • 控制塊占用額外內存(通常為 2~3 個指針大小)。
    • ?使用限制?:

      • 必須通過?lock()?獲取?std::shared_ptr?后才能訪問對象。
      • 無法直接訪問對象的原始指針(需先調用?lock())。

    ?總結?

    std::weak_ptr?通過 ?共享控制塊? 和 ?分離強/弱引用計數? 的機制,實現了對?std::shared_ptr?管理對象的安全觀測。其核心價值在于:

    1. ?打破循環引用?,避免內存泄漏。
    2. ?臨時訪問資源?,確保訪問時對象存活。
      它是現代 C++ 內存管理中不可或缺的工具,尤其適用于觀察者模式、緩存管理等場景。

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/bicheng/75006.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75006.shtml
    英文地址,請注明出處:http://en.pswp.cn/bicheng/75006.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    【ManiSkill】環境success條件和reward函數學習筆記

    1. “PickCube-v1” info["success"]&#xff1a;用于指示任務是否成功完成 布爾型張量&#xff0c;在環境的evaluate()方法中計算并返回&#xff1a; "success": is_obj_placed & is_robot_static這確保了機器人不僅能將物體準確放置在目標位置&am…

    用空閑時間做了一個小程序-二維碼生成器

    一直在摸魚中賺錢的大家好呀~ 先向各位魚友們匯報一下情況&#xff0c;目前小程序已經有900的魚友注冊使用過。雖然每天都有新的魚友注冊&#xff0c;但是魚友增長的還很緩慢。自從國慶前的文字轉語音的工具上線到現在已經將近有1個月沒有更新小程序了。但是今天終終終終終于又…

    31天Python入門——第14天:異常處理

    你好&#xff0c;我是安然無虞。 文章目錄 異常處理1. Python異常2. 異常捕獲try-except語句捕獲所有的異常信息獲取異常對象finally塊 3. raise語句4. 自定義異常5. 函數調用里面產生的異常補充練習 異常處理 1. Python異常 Python異常指的是在程序執行過程中發生的錯誤或異…

    PyQt6實例_批量下載pdf工具_使用pyinstaller與installForge打包成exe文件

    目錄 前置&#xff1a; 步驟&#xff1a; step one 準備好已開發完畢的項目代碼 step two 安裝pyinstaller step three 執行pyinstaller pdfdownload.py&#xff0c;獲取初始.spec文件 step four 修改.spec文件&#xff0c;將data文件夾加入到打包程序中 step five 增加…

    Axure項目實戰:智慧城市APP(完整交互匯總版)

    親愛的小伙伴&#xff0c;在您瀏覽之前&#xff0c;煩請關注一下&#xff0c;在此深表感謝&#xff01; 課程主題&#xff1a;智慧城市APP 主要內容&#xff1a;主功能&#xff08;社保查詢、醫療信息、公交查詢等&#xff09;、活動、消息、我的頁面匯總 應用場景&#xff…

    Appium Inspector使用教程

    1.下載最新版本 https://github.com/appium/appium-inspector/releases 2.本地啟動一個Appium服務 若Android SDK已安裝Appium服務&#xff0c;則在任意terminal使用appium啟動服務即可 3.Appium Inspector客戶端配置連接到Appium服務 Configuring and Starting a Session…

    Pycharm(七):幾個簡單案例

    一.剪刀石頭布 需求&#xff1a;和電腦玩剪刀石頭布游戲 考察點&#xff1a;1.隨機數&#xff1b;2.判斷語句 import random # numrandom.randint(1,3) # print(num) # print(**30) #1.錄入玩家手勢 playerint(input(請輸入手勢&#xff1a;&#xff08;1.剪刀 2.石頭 3&…

    Python Cookbook-4.13 獲取字典的一個子集

    任務 你有一個巨大的字典&#xff0c;字典中的一些鍵屬于一個特定的集合&#xff0c;而你想創建一個包含這個鍵集合及其對應值的新字典。 解決方案 如果你不想改動原字典: def sub_dict(somedict,somekeys,default None):return dict([(k, somedict.get(k,default)) for k…

    VMware Ubuntu 網絡配置全攻略:從斷網到暢通無阻

    一、網絡連接模式選擇&#xff08;先搞懂原理&#xff09; VMware提供三種網絡模式&#xff0c;就像手機的不同網絡套餐&#xff1a; 模式適用場景特點類比NAT個人上網/新手首選虛擬機共享主機IP&#xff0c;能上網但隱身家用WiFi橋接服務器/需要被局域網訪問虛擬機會獲得獨立…

    鏈表(C++)

    這是本人第二次學習鏈表&#xff0c;第一次學習鏈表是在大一上的C語言課上&#xff0c;首次接觸&#xff0c;感到有些難&#xff1b;第二次是在大一下學習數據結構時&#xff08;就是這次&#xff09;&#xff0c;使用C再次理解鏈表。同時&#xff0c;這也是開啟數據結構學習寫…

    【SPP】藍牙串口協議應用層深度解析:從連接建立到實戰開發

    目錄 一、SPP應用層協議框架與角色模型 1.1 分層協議棧模型 1.2 設備角色模型&#xff08;DevA 與 DevB 交互&#xff09; 二、連接建立流程&#xff1a;從 SDP 到 RFCOMM 2.1 服務發現&#xff08;SDP&#xff09;流程&#xff08;SDP 記錄關鍵參數&#xff09; 2.2 連接…

    Giteki 認證:無線產品進入日本市場的關鍵保障

    目錄 適用產品認證范圍 認證項目及技術要求 認證流程 認證周期 與其他認證的對比 常見問題 注意事項 Giteki 認證&#xff0c;其名稱來源于日本語 “技適マーク”&#xff0c;羅馬字拼寫為 “GITEKI” &#xff0c;在行業內也常被稱為 Telec 認證、MIC 認證、RF 認證或技…

    Ubuntu24.04 配置遠程桌面服務

    一&#xff1a;安裝 sudo apt update sudo apt install vino 二&#xff1a;設置 gsettings set org.gnome.Vino require-encryption false # 關閉加密&#xff08;某些 VNC 客戶端不支持加密&#xff09; gsettings set org.gnome.Vino prompt-enabled false # 關閉連接…

    人工智能與軟件工程結合的發展趨勢

    AI與軟件工程的結合正在深刻改變軟件開發的流程、工具和方法&#xff0c;其發展方向涵蓋了從代碼生成到系統維護的整個生命周期。以下是主要的發展方向和技術趨勢&#xff1a; 1. 軟件架構體系的重構 從“面向過程”到“面向目標”的架構轉型&#xff1a; AI驅動軟件設計以目標…

    轉發和重定向的區別詳解

    轉發&#xff08;Forward&#xff09;和重定向&#xff08;Redirect&#xff09;是 Web 開發中兩種常用的請求處理方式&#xff0c;主要用于將客戶端請求從一個資源轉移到另一個資源。它們在實現機制、行為表現和應用場景上有顯著區別&#xff0c;以下是對兩者的詳細解析&#…

    python專題1-----判斷一個變量是否是字符串類型

    在 Python 中&#xff0c;可以使用 isinstance() 函數來判斷一個變量是否是字符串類型。字符串在 Python 中是以 str 類型表示的。下面是一些示例代碼&#xff0c;展示如何判斷一個變量是否是字符串類型&#xff1a; # 示例變量 var1 "Hello, World!" var2 12345 …

    軟件工程之需求工程(需求獲取、分析、驗證)

    一、需求獲取&#xff08;Requirements Elicitation&#xff09; 1. 定義與目標 需求獲取是通過與用戶、利益相關者等交互&#xff0c;識別并捕獲系統需求的過程&#xff0c;目標是明確用戶意圖與業務目標&#xff0c;避免后期因需求偏差導致返工。 2. 主要方法 問卷法&…

    Java簡單生成pdf

    生成這樣的PDF 直接上代碼 public static void main(String[] args) {String logoPath "Q:\\IdeaWork\\Demo\\src\\main\\webapp\\images\\logo.jpg"; // 替換為實際路徑String baseDir "E:/Demo/TEST/problem/Generate"; // 基礎目錄int year 2025; //…

    k8s存儲介紹(六)StorangeClass

    一、Kubernetes 存儲類&#xff08;StorageClass&#xff09;詳解 1. 什么是 StorageClass&#xff1f; 在 Kubernetes 中&#xff0c;StorageClass&#xff08;存儲類&#xff09;是一種用于動態創建 PersistentVolume&#xff08;PV&#xff09;的資源對象。它允許管理員根…

    C++:allocator類(動態數組續)

    1.為什么需要 allocator&#xff1f; 在 C 中&#xff0c;動態內存管理通常通過 new 和 delete 完成&#xff1a; int* p new int; // 分配內存 構造對象 delete p; // 析構對象 釋放內存 但 new 和 delete 有兩個問題&#xff1a; 耦合性&#xff1a;將內…