std::shared_ptr引起內存泄漏的例子

目錄

一、循環引用(最常見場景)

示例代碼

內存泄漏原因

二、共享指針管理的對象包含自身的?shared_ptr

示例代碼

內存泄漏(或雙重釋放)原因

三、解決方案

1. 循環引用:使用?std::weak_ptr

2. 對象獲取自身的?shared_ptr:繼承?std::enable_shared_from_this

四、其他潛在風險

1. 混合使用原始指針和?shared_ptr

2. 數組管理

總結


std::shared_ptr?是 C++ 中用于管理動態內存的智能指針,通過引用計數機制自動釋放對象。但在某些場景下,它仍可能導致內存泄漏。以下通過具體例子說明:

一、循環引用(最常見場景)

示例代碼
#include <iostream>
#include <memory>class B;  // 前向聲明class A {
public:std::shared_ptr<B> b_ptr;~A() { std::cout << "A destroyed" << std::endl; }
};class B {
public:std::shared_ptr<A> a_ptr;~B() { std::cout << "B destroyed" << std::endl; }
};int main() {auto a = std::make_shared<A>();  // a的引用計數為1auto b = std::make_shared<B>();  // b的引用計數為1a->b_ptr = b;  // b的引用計數變為2b->a_ptr = a;  // a的引用計數變為2// main函數結束時:// a和b的引用計數減1,但仍為1(互相持有對方的shared_ptr)// 導致兩者的析構函數都不會被調用,內存泄漏!return 0;
}
內存泄漏原因
  1. a?和?b?互相持有對方的?shared_ptr,形成循環引用。
  2. 當?main?函數結束時,a?和?b?的局部變量被銷毀,引用計數減 1,但仍為 1(因為對方的成員變量還持有自己的指針)。
  3. 引用計數永遠無法降為 0,導致析構函數不會被調用,內存無法釋放。

二、共享指針管理的對象包含自身的?shared_ptr

示例代碼
#include <iostream>
#include <memory>class Bad {
public:std::shared_ptr<Bad> getSelf() {return std::shared_ptr<Bad>(this);  // 危險!}~Bad() { std::cout << "Bad destroyed" << std::endl; }
};int main() {auto b1 = std::make_shared<Bad>();auto b2 = b1->getSelf();  // 創建了第二個獨立的shared_ptr管理同一對象// b1和b2的引用計數均為1// main函數結束時,b1和b2分別析構,導致對象被delete兩次(雙重釋放)return 0;
}
內存泄漏(或雙重釋放)原因
  1. getSelf()?方法中使用?this?指針創建了一個新的?shared_ptr,與原?shared_ptr?無關。
  2. 同一對象被兩個獨立的?shared_ptr?管理,引用計數各自為 1。
  3. 當兩個?shared_ptr?析構時,對象被重復釋放,導致未定義行為(通常是程序崩潰)。

三、解決方案

1. 循環引用:使用?std::weak_ptr

std::weak_ptr?是一種弱引用,不增加引用計數,用于打破循環:

class A {
public:std::weak_ptr<B> b_ptr;  // 改為weak_ptr~A() { std::cout << "A destroyed" << std::endl; }
};class B {
public:std::weak_ptr<A> a_ptr;  // 改為weak_ptr~B() { std::cout << "B destroyed" << std::endl; }
};
  • weak_ptr?不會增加引用計數,當?a?和?b?局部變量銷毀時,引用計數降為 0,對象正常釋放。
2. 對象獲取自身的?shared_ptr:繼承?std::enable_shared_from_this
#include <memory>class Good : public std::enable_shared_from_this<Good> {
public:std::shared_ptr<Good> getSelf() {return shared_from_this();  // 安全!}~Good() { std::cout << "Good destroyed" << std::endl; }
};
  • shared_from_this()?返回一個與已有?shared_ptr?共享引用計數的新指針,避免雙重釋放。

四、其他潛在風險

1. 混合使用原始指針和?shared_ptr
int* raw = new int(42);
std::shared_ptr<int> ptr1(raw);
std::shared_ptr<int> ptr2(raw);  // 錯誤!兩個獨立的shared_ptr管理同一內存
  • 同一原始指針被多個?shared_ptr?獨立管理,導致雙重釋放。
2. 數組管理

std::shared_ptr?默認使用?delete?釋放對象,若管理數組需自定義刪除器:

std::shared_ptr<int[]> arr(new int[10]);  // 錯誤!默認使用delete而非delete[]
std::shared_ptr<int> arr(new int[10], [](int* p) { delete[] p; });  // 正確

總結

std::shared_ptr?內存泄漏的核心原因是引用計數無法降為 0,常見于循環引用和錯誤的指針管理。使用?std::weak_ptr?和?std::enable_shared_from_this?可有效避免這些問題。在實際開發中,應盡量避免手動管理原始指針,確保所有動態內存都由智能指針統一管理。

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

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

相關文章

AI 知識數據庫搭建方案:從需求分析到落地實施

AI 知識數據庫的搭建需結合業務場景、數據特性與技術架構&#xff0c;形成系統化解決方案。以下是一套完整的搭建框架&#xff0c;涵蓋規劃、設計、實施及優化全流程&#xff1a; 一、前期規劃&#xff1a;需求分析與目標定義 1. 明確業務場景與知識需求 場景導向&#xff1a…

Tensorflow 基礎知識:變量、常量、占位符、Session 詳解

在深度學習領域,TensorFlow 是一個廣泛使用的開源機器學習框架。想要熟練使用 TensorFlow 進行模型開發,掌握變量、常量、占位符和 Session 這些基礎知識是必不可少的。接下來,我們就深入了解一下它們的概念、用處,并通過代碼示例進行演示。 一、常量(Constant) 常量,顧…

linux 常見問題之如何清除大文件的內容

linux 常見問題之如何清除大文件的內容 在 Linux 系統中&#xff0c;我們有時會遇到文件隨著時間增長變得巨大&#xff0c;最常見的就是服務器的日志文件&#xff0c;隨著時間的推移占用大量的磁盤空間&#xff0c;下面介紹如何清楚大文件的內容&#xff0c;當然避免文件內容過…

薛定諤的貓思想實驗如何推演到量子計算

前言 這是我的選修課作業&#xff0c;但是我并不喜歡小論文方式的寫法&#xff0c;死板又老套。先在這打一份底稿。 薛定諤的貓 可能一說到量子這個關鍵詞&#xff0c;大家第一時間都會想到的是“薛定諤的貓”。 實驗介紹 薛定諤的貓是一個著名的思想實驗&#xff0c;由奧…

嵌入式開發中fmacro-prefix-map選項解析

在嵌入式開發中&#xff0c;-fmacro-prefix-map 是 GCC 和 Clang 等編譯器提供的一個路徑映射選項&#xff0c;主要用于在預處理階段重寫宏定義中出現的絕對路徑。它的核心目的是解決以下問題&#xff1a; 核心作用 構建可重現性 消除編譯輸出&#xff08;如 .o、.d 文件&…

Javaweb學習——day3(Servlet 中處理表單數據)

文章目錄 一、概念學習1. GET vs POST 請求方式的區別2. HttpServletRequest 獲取表單數據 二、代碼講解與練習第 1 步&#xff1a;在 webapp 下創建 login.html第 2 步&#xff1a;在 com.example 包下創建 LoginServlet第 3 步&#xff1a;修改 web.xml 注冊 LoginServlet第 …

在 iOS 開發中單獨解析域名為 IP

1 為什么要自己解析? 典型場景說明劫持/污染檢測比較 系統解析 與 自建 DNS 的差異QoS / CDN 選路對每個候選 IP 做 RT/丟包測速系統 API(NSURLSession / Network.framework)在「真正建立連接之前」不會把解析結果暴露出來,因此需要主動解析一步。 2 API 選型概覽 API是否過…

YOLOv1 技術詳解:正負樣本劃分與置信度設計

&#x1f50d; YOLOv1 技術詳解&#xff1a;正負樣本劃分與置信度設計 一、前言 YOLOv1 是目標檢測領域中具有劃時代意義的算法之一&#xff0c;它將檢測任務統一為一個回歸問題&#xff0c;實現了“You Only Look Once”的端到端實時檢測。其中&#xff0c;正負樣本的劃分機…

為 Nginx 配置 HTTPS(以 n8n 為例)完整教程【CentOS 7】

在部署如 n8n 這類自動化平臺時&#xff0c;為了保障數據傳輸安全&#xff0c;我們通常會使用 HTTPS 訪問。本文將以 n8n.example.com 為例&#xff0c;介紹如何在 CentOS 7 系統中通過 Nginx 為本地運行在端口 5678 的 n8n 服務配置免費 SSL 證書&#xff08;Let’s Encrypt&a…

Elasticsearch從安裝到實戰、kibana安裝以及自定義IK分詞器/集成整合SpringBoot詳細的教程ES(四)查詢、排序、分頁、高亮

基礎代碼 package com.test.xulk;import com.alibaba.fastjson.JSON; import com.test.xulk.es.esdoc.HotelDoc; import com.test.xulk.es.service.IHotelService; import org.apache.http.HttpHost; import org.elasticsearch.action.search.SearchRequest; import org.elast…

一個數組樣式上要分成兩個

如圖所示&#xff0c;要有一個區分來顯示&#xff0c;如果一開始就是這樣還可以有很多種處理方式&#xff0c;但是這個后期一直在調整所以不好重做因為開發已經完成&#xff0c;加上很多地方聯動改的地方太多&#xff0c;所以采用了一個比較笨的方法 <ul class"classif…

NLP進化史:從規則模板到思維鏈推理,七次范式革命全解析

“語言不是神的創造物&#xff0c;而是平凡人類的產物。”——諾姆喬姆斯基 自然語言處理&#xff08;NLP&#xff09;的發展史&#xff0c;就是人類試圖教會機器理解語言本質的探索史。本文將帶您穿越70年技術長河&#xff0c;揭示NLP領域關鍵的范式轉換里程碑。 一、規則驅動…

Yarn與NPM緩存存儲目錄遷移

Yarn與NPM緩存存儲目錄遷移 背景與需求 解釋Yarn和NPM緩存機制的作用及默認存儲路徑遷移緩存目錄的常見原因&#xff08;如磁盤空間不足、系統盤性能優化、多項目協作需求&#xff09; Yarn緩存目錄遷移方法 查看當前Yarn緩存目錄的命令&#xff1a;yarn cache dir修改Yarn…

Python爬蟲-批量爬取快手視頻并將視頻下載保存到本地

前言 本文是該專欄的第80篇,后面會持續分享python爬蟲干貨知識,記得關注。 本文筆者以快手為例子,基于Python爬蟲來實現批量采集視頻,并將視頻下載以及保存到本地。 而具體的“視頻采集以及視頻下載,保存”思路邏輯,筆者將在正文中結合“完整代碼”來詳細介紹每個步驟。…

org.springframework.cloud.openfeign 組件解釋

我們來詳細解釋一下 org.springframework.cloud.openfeign 這個組件。 一句話概括&#xff1a;它是一個聲明式的、模板化的HTTP客戶端&#xff0c;旨在讓微服務之間的REST API調用變得像調用本地方法一樣簡單。 為了讓你徹底理解&#xff0c;我會從以下幾個方面來解釋&#x…

2025年06月13日Github流行趨勢

項目名稱&#xff1a;awesome-llm-apps 項目地址url&#xff1a;https://github.com/Shubhamsaboo/awesome-llm-apps項目語言&#xff1a;Python歷史star數&#xff1a;37,536今日star數&#xff1a;1,287項目維護者&#xff1a;Shubhamsaboo, Madhuvod, libw0430, AndrewHoh, …

Go語言底層(五): 深入淺出Go語言的ants協程池

在 Go 語言中&#xff0c;goroutine 的輕量特性使得高并發編程變得異常簡單。然而&#xff0c;隨著并發量的增加&#xff0c;頻繁創建對象和無限制啟動 goroutine 也可能帶來內存浪費、GC 壓力和資源搶占等問題。為了解決這些隱患&#xff0c;協程池成為常用的優化手段。用于控…

React Native【實戰范例】網格導航 FlatList

import React from "react"; import {FlatList,Image,SafeAreaView,StyleSheet,Text,View, } from "react-native"; interface GridItem {id: string;title: string;imageUrl: string; } // 網格布局數據 const gridData Array.from({ length: 30 }, (_, …

KJY0047-J1階段測試

KJY0047 - J1階段測試題解 題目1&#xff1a;SYAP0001. 闖關 解題思路&#xff1a; 暴力思路&#xff1a;每次碰到奇數都使用一次 f o r for for 循環將后續的數值 1 1 1, 時間復雜度 O ( n 2 ) O(n^2) O(n2) 優化思路&#xff1a;可以用一個計數器 c n t cnt cnt 來存…

鍵盤按鍵枚舉 Key 說明文檔

鍵盤按鍵枚舉 Key 說明文檔 該文檔介紹了 Key 枚舉中定義的鍵盤按鍵常量及其對應編號&#xff0c;適用于標準 105 鍵的美式鍵盤布局。常用于瀏覽器或桌面端的鍵盤事件監聽、游戲開發、快捷鍵映射等場景。 electron-jest ?? 功能鍵&#xff08;Function Keys&#xff09; …