0

0

c++中如何使用std::shared_ptr的循环引用检查工具_c++内存调试【实例】

尼克

尼克

发布时间:2026-01-18 05:53:12

|

607人浏览过

|

来源于php中文网

原创

std::shared_ptr无内置循环引用检测机制,依赖weak_ptr打断持有链并结合ASan/valgrind定位泄漏;典型场景如父子关系中子持父需用weak_ptr,析构日志与泄漏报告协同排查。

c++中如何使用std::shared_ptr的循环引用检查工具_c++内存调试【实例】

std::shared_ptr 本身没有内置循环引用检查工具

这是最常被误解的一点:std::shared_ptr 不提供运行时循环引用检测能力。它的引用计数只管“谁还持有我”,不管“我是否间接指向了自己”。一旦形成 A → B → A 这样的 shared_ptr 持有链,引用计数永不归零,对象永远不析构——内存泄漏就发生了,且无任何警告。

所以所谓“循环引用检查工具”,实际是靠开发者主动规避 + 外部调试手段定位,而非 std::shared_ptr 自带功能。

用 std::weak_ptr 打断循环是最直接的修复方式

在可能构成闭环的持有关系中,把其中一端改为 std::weak_ptr,就能让引用计数不再计入它,从而打破循环。典型场景是父子对象、观察者-被观察者、双向链表节点。

  • 父类持子类用 std::shared_ptr,子类持父类必须用 std::weak_ptr
  • 调用 weak_ptr.lock() 获取临时 shared_ptr,若返回空说明父对象已销毁
  • 绝不能在构造函数里用 shared_from_this() 初始化同对象的 shared_ptr 成员(易触发隐式循环)
class Node {
public:
    std::shared_ptr next;
    std::weak_ptr prev; // ← 关键:这里不用 shared_ptr
};

用 AddressSanitizer + UBSan 捕获疑似循环引用导致的泄漏

虽然不能直接标出“此处有循环引用”,但 ASan 的内存泄漏报告能帮你定位长期存活却本该释放的对象。配合自定义析构日志,可反向推断问题链。

FlowIn
FlowIn

AI 时代下的内容共创平台,借助 FlowIn AI 撰写与改写内容十分便利。

下载

立即学习C++免费学习笔记(深入)”;

  • 编译时加 -fsanitize=address,undefined -fno-omit-frame-pointer
  • 运行后若输出类似 LEAK: 123 byte(s) in 4 allocation(s),说明有对象未释放
  • 在类析构函数里加 std::cout ,对比哪些地址没出现
  • 注意:ASan 不报告循环引用本身,只报告最终结果——泄漏;需结合对象生命周期逻辑排查

用 valgrind --leak-check=full 定位泄漏源头(Linux/macOS)

valgrind 能给出完整的分配回溯,比 ASan 更适合深挖长期驻留对象的创建路径。

  • 运行命令:valgrind --leak-check=full --show-leak-kinds=all ./your_program
  • 重点关注 definitely loststill reachable 块——后者往往是循环引用的典型表现
  • 若看到某类对象的 new 调用栈反复出现在多个“still reachable”块中,且它们互相持有 shared_ptr,基本可锁定循环
  • valgrind 无法识别 weak_ptr 语义,所以你得人工对照代码判断哪条持有链该改用 weak_ptr

循环引用不是语法错误,编译器不会报错,运行时也不会崩溃——它安静地吃掉内存,直到某天 OOM。真正难的不是修复,而是意识到“这个对象怎么还没析构?”背后可能藏着一个跨模块、跨线程、甚至跨 shared_ptr 生命周期的隐式闭环。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

391

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

572

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

481

2023.08.10

undefined是什么
undefined是什么

undefined是代表一个值或变量不存在或未定义的状态。它可以作为默认值来判断一个变量是否已经被赋值,也可以用于设置默认参数值。尽管在不同的编程语言中,undefined可能具有不同的含义和用法,但理解undefined的概念可以帮助我们更好地理解和编写程序。本专题为大家提供undefined相关的各种文章、以及下载和课程。

4875

2023.07.31

网页undefined是什么意思
网页undefined是什么意思

网页undefined是指页面出现了未知错误的意思,提示undefined一般是在开发网站的时候定义不正确或是转换不正确,或是找不到定义才会提示undefined未定义这个错误。想了解更多的相关内容,可以阅读本专题下面的文章。

2973

2024.08.14

网页undefined啥意思
网页undefined啥意思

本专题整合了undefined相关内容,阅读下面的文章了解更多详细内容。后续继续更新。

199

2025.12.25

macOS怎么切换用户账户
macOS怎么切换用户账户

在 macOS 系统中,可通过多种方式切换用户账户。如点击苹果图标选择 “系统偏好设置”,打开 “用户与群组” 进行切换;或启用快速用户切换功能,通过菜单栏或控制中心的账户名称切换;还能使用快捷键 “Control+Command+Q” 锁定屏幕后切换。

333

2025.05.09

磁盘配额是什么
磁盘配额是什么

磁盘配额是计算机中指定磁盘的储存限制,就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。php中文网为大家提供各种磁盘配额相关的内容,教程,供大家免费下载安装。

1349

2023.06.21

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

68

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.4万人学习

Git 教程
Git 教程

共21课时 | 2.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号