0

0

C++ shared_ptr循环引用怎么办 weak_ptr解决方案详解

P粉602998670

P粉602998670

发布时间:2025-08-16 18:29:01

|

1061人浏览过

|

来源于php中文网

原创

c++++中shared_ptr的循环引用问题会导致内存泄漏,解决方法是使用weak_ptr。①循环引用发生在两个或多个shared_ptr相互持有对方,引用计数无法归零;②weak_ptr不增加引用计数,仅用于临时访问对象,通过lock()获取shared_ptr;③修改类定义,将其中一个shared_ptr改为weak_ptr即可打破循环;④使用weak_ptr时应注意不能直接操作对象、避免频繁调用lock()、合理判断是否需要强引用;⑤常见踩坑场景包括观察者模式、树形结构回指和缓存系统,应优先考虑是否需要强引用以避免不必要的依赖。

C++ shared_ptr循环引用怎么办 weak_ptr解决方案详解

C++中,

shared_ptr
的循环引用问题是个常见但容易忽视的陷阱。简单来说,就是两个或多个
shared_ptr
互相持有对方,导致引用计数始终不为0,最终造成内存泄漏。

C++ shared_ptr循环引用怎么办 weak_ptr解决方案详解

解决办法是使用

weak_ptr
来打破这种循环。它不会增加对象的引用计数,只是一个“弱引用”,可以用来观察对象是否还活着,同时避免了强引用带来的循环依赖。

C++ shared_ptr循环引用怎么办 weak_ptr解决方案详解

为什么会出现循环引用?

最典型的场景就是两个类之间相互持有

shared_ptr

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

class B; // 前向声明

class A {
public:
    shared_ptr ptr;
};

class B {
public:
    shared_ptr ptr;
};

如果创建两个对象并让它们互指:

C++ shared_ptr循环引用怎么办 weak_ptr解决方案详解
auto a = make_shared();
auto b = make_shared();
a->ptr = b;
b->ptr = a;

这时候,

a
b
的引用计数都是1(外部有一个),但因为彼此也持有一个,所以即使外部不再使用,引用计数也不会变成0,无法释放资源。


weak_ptr 是怎么解决这个问题的?

用一句话说:

weak_ptr
不会影响引用计数,只用于临时访问对象

Veggie AI
Veggie AI

Veggie AI 是一款利用AI技术生成可控视频的在线工具

下载

修改上面的例子很简单,把其中一个改为

weak_ptr
即可:

class B; // 前向声明

class A {
public:
    shared_ptr ptr;
};

class B {
public:
    weak_ptr ptr; // 改成 weak_ptr
};

这样,当

a
被释放时,
b
中的
ptr
虽然还在,但它只是个“弱引用”,不会阻止
a
被销毁。之后如果想访问这个对象,需要通过
lock()
方法获取一个临时的
shared_ptr

if (auto aPtr = b->ptr.lock()) {
    // aPtr 是一个有效的 shared_ptr,可以安全使用
} else {
    // 对象已经被释放
}

使用 weak_ptr 的注意事项

  • 不能直接操作对象
    weak_ptr
    没有
    operator->
    operator*
    ,必须先调用
    lock()
    转成
    shared_ptr
  • 每次 lock() 都会产生一个新的 shared_ptr,所以要注意不要频繁调用,否则可能影响性能
  • 不是万能药:如果逻辑本身就需要保持对象存活,那就不适合用
    weak_ptr
    ,得重新设计结构

比如下面这段代码就有点滥用:

for (int i = 0; i < 100000; ++i) {
    auto tmp = myWeakPtr.lock(); // 每次都 lock,效率低
    if (tmp) tmp->doSomething();
}

应该改成:

if (auto tmp = myWeakPtr.lock()) {
    for (int i = 0; i < 100000; ++i) {
        tmp->doSomething(); // 只 lock 一次
    }
}

实际开发中哪些地方容易踩坑?

  • 观察者模式:订阅者保存的是
    shared_ptr
    ,发布者又反过来持有订阅者,容易形成循环
  • 树形结构:父子节点互相引用,父节点用
    shared_ptr
    ,子节点也应该考虑用
    weak_ptr
    回指
  • 缓存系统:缓存项持有对象的
    shared_ptr
    ,而其他模块也可能有同样的引用,如果不小心反过来引用缓存,就会出问题

遇到这些情况时,不妨多问一句:我这里真的需要一个强引用吗?如果不是必须的,就该换成

weak_ptr


基本上就这些。

weak_ptr
不是什么高级技巧,但用得好可以避免很多隐藏的内存泄漏问题。只要记住一点:不需要控制生命周期的地方,就尽量别用
shared_ptr

相关专题

更多
云朵浏览器入口合集
云朵浏览器入口合集

本专题整合了云朵浏览器入口合集,阅读专题下面的文章了解更多详细地址。

0

2026.01.20

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

20

2026.01.20

PS使用蒙版相关教程
PS使用蒙版相关教程

本专题整合了ps使用蒙版相关教程,阅读专题下面的文章了解更多详细内容。

62

2026.01.19

java用途介绍
java用途介绍

本专题整合了java用途功能相关介绍,阅读专题下面的文章了解更多详细内容。

87

2026.01.19

java输出数组相关教程
java输出数组相关教程

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

39

2026.01.19

java接口相关教程
java接口相关教程

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

10

2026.01.19

xml格式相关教程
xml格式相关教程

本专题整合了xml格式相关教程汇总,阅读专题下面的文章了解更多详细内容。

13

2026.01.19

PHP WebSocket 实时通信开发
PHP WebSocket 实时通信开发

本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

19

2026.01.19

微信聊天记录删除恢复导出教程汇总
微信聊天记录删除恢复导出教程汇总

本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

160

2026.01.18

热门下载

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

精品课程

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

共94课时 | 7.1万人学习

C 教程
C 教程

共75课时 | 4.1万人学习

C++教程
C++教程

共115课时 | 13万人学习

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

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