0

0

C++中std::shared_ptr的循环引用如何通过weak_ptr解决? (引用计数陷阱)

穿越時空

穿越時空

发布时间:2026-02-14 19:09:55

|

234人浏览过

|

来源于php中文网

原创

std::shared_ptr循环引用会导致内存泄漏,因引用计数无法归零;应使用weak_ptr打破循环,仅一方用shared_ptr持有,另一方用weak_ptr观察,并通过lock()安全访问。

c++中std::shared_ptr的循环引用如何通过weak_ptr解决? (引用计数陷阱)

std::shared_ptr 循环引用会导致内存泄漏

当两个 std::shared_ptr 相互持有对方管理的对象时,引用计数永远无法归零,对象永远不会析构。这不是 bug,是设计使然——shared_ptr 只看“还有谁在用”,不关心“谁在用谁”。

典型场景:双向链表节点、父子对象(如树节点)、观察者与被观察者之间用 shared_ptr 互相保存。

现象:程序结束前内存占用持续增长,Valgrind 或 ASan 报告“still reachable”块,对象的析构函数根本不执行。

用 weak_ptr 打断循环中的一个引用链

weak_ptr 不增加引用计数,只“观察”对象是否还活着。它必须配合 lock() 升级为 shared_ptr 才能安全访问对象,且升级失败时返回空 shared_ptr

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

LogoMaker
LogoMaker

免费在线制作Logo,在几分钟内完成标志设计

下载

关键原则:循环中**只有一方用 shared_ptr 持有,另一方改用 weak_ptr**。比如父节点用 shared_ptr 持有子节点,子节点用 weak_ptr 回指父节点。

  • 不要在构造函数里直接用 weak_ptrlock() 结果初始化成员 shared_ptr,容易引发未定义行为
  • 访问前必须调用 lock() 并检查返回值,不能假设对象一定存在
  • weak_ptr 本身不参与资源管理,析构开销极小,但频繁 lock() 有原子操作成本

示例:

struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev; // 不再用 shared_ptr
};

auto a = std::make_shared<Node>();
auto b = std::make_shared<Node>();
a->next = b;
b->prev = a; // 此时 b 不延长 a 的生命周期

weak_ptr::lock() 返回空 shared_ptr 的常见原因

不是所有 weak_ptr 失效都意味着你写错了,但得知道为什么失效:

  • 被观察的 shared_ptr 已全部析构(正常)
  • 对象在多线程中被另一个线程释放,而本线程的 weak_ptr 还没来得及 lock()(需同步)
  • 误把临时 shared_ptr 赋给 weak_ptr,比如 wptr = std::make_shared<t>();</t> 后立刻离开作用域,临时对象销毁

错误写法:

std::weak_ptr<int> wp;
{
    auto sp = std::make_shared<int>(42);
    wp = sp; // OK
} // sp 析构 → wp now expired
auto sp2 = wp.lock(); // sp2.get() == nullptr

std::enable_shared_from_this 是弱引用的辅助工具

当你需要从对象内部安全地生成指向自身的 shared_ptr(比如回调、异步任务),直接用 this 构造会破坏引用计数——此时必须继承 std::enable_shared_from_this<t></t>

它内部持有一个 weak_ptr,由首次创建的 shared_ptr 初始化。所以:

  • 必须通过 shared_ptr 创建对象(如 make_shared),否则 shared_from_this()std::bad_weak_ptr
  • weak_from_this() 是 C++17 新增,可直接拿到那个内部 weak_ptr,适合做延迟访问或观察
  • 不要在构造函数里调用 shared_from_this(),此时内部 weak_ptr 还没被初始化

典型误用:

struct Good : std::enable_shared_from_this<Good> {
    void go() {
        auto self = shared_from_this(); // OK,前提是 this 来自 shared_ptr
    }
};

// 错误:
Good g;
g.shared_from_this(); // 抛异常

循环引用真正的复杂点不在语法,而在逻辑所有权的划分:哪个模块“真正拥有”这个对象?weak_ptr 不是补丁,是所有权模型的显式声明。一旦开始用,就得全程按这个契约来——比如子节点访问父节点前,必须接受“父节点可能已不存在”这个事实。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
线程和进程的区别
线程和进程的区别

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

673

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

325

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

24

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

24

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

94

2026.02.06

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

23

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

11

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

7

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

8

2026.02.13

热门下载

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

精品课程

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

共94课时 | 9.4万人学习

C 教程
C 教程

共75课时 | 4.7万人学习

C++教程
C++教程

共115课时 | 17.7万人学习

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

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