0

0

怎样处理C++中的环形引用问题 weak_ptr打破循环引用技巧

P粉602998670

P粉602998670

发布时间:2025-07-09 11:34:01

|

288人浏览过

|

来源于php中文网

原创

环形引用指两个或多个shared_ptr相互引用导致内存泄漏。例如,结构体a和b各自持有对方的shared_ptr,当main函数结束时,它们的引用计数均不为0,无法释放。解决方法是使用weak_ptr打破循环,weak_ptr不会增加引用计数,仅观察对象。其使用步骤包括:1. 将其中一个shared_ptr改为weak_ptr;2. 使用lock()转换为shared_ptr并检查对象是否存在;3. 在合适场景如观察者模式、缓存系统、树结构中应用。注意事项包括避免频繁调用lock()、控制shared_ptr生命周期。

怎样处理C++中的环形引用问题 weak_ptr打破循环引用技巧

在C++中使用智能指针时,shared_ptr虽然能自动管理内存,但如果对象之间存在相互引用,就很容易导致环形引用(循环引用),从而引发内存泄漏。这时候,就需要用到weak_ptr来打破这个循环。

怎样处理C++中的环形引用问题 weak_ptr打破循环引用技巧

什么是环形引用?

环形引用指的是两个或多个shared_ptr对象彼此持有对方的引用,导致它们的引用计数永远不为0,即使这些对象已经不再被外部使用,也无法释放。

怎样处理C++中的环形引用问题 weak_ptr打破循环引用技巧

举个常见的例子:

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

struct B;

struct A {
    shared_ptr b_ptr;
};

struct B {
    shared_ptr a_ptr;
};

int main() {
    auto a = make_shared();
    auto b = make_shared();
    a->b_ptr = b;
    b->a_ptr = a;
}

在这个例子中,ab互相通过shared_ptr持有对方,当main函数结束时,ab的引用计数都还是1,所以不会释放,造成内存泄漏。

怎样处理C++中的环形引用问题 weak_ptr打破循环引用技巧

weak_ptr的作用:打破循环

weak_ptr是一个弱引用指针,它不会增加所指向对象的引用计数。也就是说,它观察一个由shared_ptr管理的对象,但不会阻止该对象被销毁。

XPaper Ai
XPaper Ai

AI撰写论文、开题报告生成、AI论文生成器尽在XPaper Ai论文写作辅助指导平台

下载

解决上面的例子,只需要将其中一个引用改为weak_ptr

struct A;

struct B {
    weak_ptr a_ptr;  // 改为 weak_ptr
};

struct A {
    shared_ptr b_ptr;
};

这样,当a被释放时,b中的a_ptr会变成“过期”的状态,而不会影响对象的释放流程。


如何正确使用weak_ptr?

使用weak_ptr需要注意几个关键点:

  • 不能直接访问对象内容,需要先转换成shared_ptr
  • 转换前要检查对象是否还存在(是否“过期”)

基本使用步骤如下:

weak_ptr wp;

{
    shared_ptr sp = make_shared();
    wp = sp;
}  // sp离开作用域后,对象被释放

if (auto sp = wp.lock()) {  // lock()返回shared_ptr
    // 使用sp操作对象
} else {
    // 对象已被释放
}

常见使用场景包括:

  • 观察者模式中,避免订阅者和发布者之间形成循环引用
  • 缓存系统中,避免缓存项长期持有资源
  • 树结构中父子节点之间的引用关系

小技巧与注意事项

  • 如果你发现某个对象应该被释放却没有释放,可以怀疑是不是出现了循环引用。
  • weak_ptr本身没有“悬空”问题,因为它不拥有对象所有权。
  • lock()返回的shared_ptr会延长对象生命周期,适合在多线程环境中安全地访问对象。
  • 不要频繁调用lock()并重复使用同一个shared_ptr副本,应尽量控制其生命周期范围。

总的来说,处理C++中的环形引用问题,最常用也最有效的方法就是使用weak_ptr来替代其中一环的shared_ptr。虽然看起来简单,但在设计复杂对象关系时非常实用。
基本上就这些。

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

193

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

186

2025.07.04

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

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

472

2023.08.10

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

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

107

2025.12.24

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

4

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

7

2025.12.31

出现404解决方法大全
出现404解决方法大全

本专题整合了404错误解决方法大全,阅读专题下面的文章了解更多详细内容。

42

2025.12.31

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

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

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