当前位置: 首页 > news >正文

图解C++智能指针的循环引用

欢迎大家访问我的个人主页guts的小屋

循环引用是学习智能指针过程中的一个小难点,笔者愚钝,明明知道是两个指针互相引用导致了内存泄漏,但看各种文字资料时,脑子里总是一团浆糊,感觉似懂非懂,于是自己绘制了几张图片,思路和概念才清晰起来,希望这篇博客能帮助有同样困惑的同学解惑。

shared_ptr 的实现

要明白循环引用,我们首先需要知道shared_ptr是如何实现的,它内部包含两个指针,一个指向我们要管理的资源对象,另一个指向则指向这个对象所对应的控制块。在这个控制块中,包含了这个对象的强引用计数,当我们第一次声明一个shared_ptr变量时,就会为这个资源对象分配一个控制块,并将强引用计数初始化为1。
当有新的shared_ptr对象拥有这个资源的时候,强引用计数就会+1,当shared_ptr对象销毁或者调用.reset()方法时,强引用计数就会-1,当强引用计数为0时,这个资源就会析构。这样我们就通过RAII来避免了内存的泄露。

循环引用

这看起来是一个很完美的设计,但是shared_ptr管理的资源和shared_ptr对象本身是两块内存,并且shared_ptr管理的资源本身也可以包含一个shared_ptr对象并持有资源,这样就会导致,一旦两个资源本身互相持有,那么他们析构的条件就是对方析构,这就会导致内存的泄露。

这么说可能有些模糊,我们直接来看例子:

class A {
public:std::shared_ptr<A> ptr;...
}
int main() {// code Istd::shared_ptr<A> a = std::make_shared<A>();std::shared_ptr<A> b = std::make_shared<A>(); // code IIa->ptr = b;b->ptr = a;return 0;
}

code I 运行完毕后,我们会在堆中创建两个A类的对象,我们将其称之为OBJ_AOBJ_B,同时栈上会有两个std::shared_ptr<A>对象ab,他们分别指向OBJ_AOBJ_B以及他们各自的控制块CB_ACB_B,如下图所示
image
此时两个控制块的引用计数都是1,当我们运行Code II后,OBJ_AOBJ_B会拥有对对方的所有权,他们的引用计数都变为2
image
这个时候代码运行完毕,ab作为栈上的对象被销毁,OBJ_AOBJ_B的引用计数都下降为1,但是由于此时他们都持有指向彼此的shared_ptr对象,引用计数仍为1,不会继续下降,这块内存就不会被释放,造成了内存泄露。
image

weak_ptr的引入

为了解决这个问题,我们引入了weak_ptr,它不拥有资源的所有权,指向资源的时候只会增加弱引用计数而非强引用计数,弱引用计数不决定资源的生命周期,只决定控制块的生命周期,当弱引用计数为0时销毁控制块。
需要注意的是,shared_ptr也会让弱引用计数+1。

class A {
public:std::weak_ptr<A> ptr;...
}
int main() {std::shared_ptr<A> a = std::make_shared<A>();std::shared_ptr<A> b = std::make_shared<A>();a->ptr = b;b->ptr = a;return 0;
}

当我们使用上面的代码时,几个对象的声明周期如下图所示:
image
ba离开作用域后

  1. b析构,CB_B的强引用计数-1为0,弱引用计数-1=1

  2. OBJ_B析构,CB_A的弱引用计数-1=1

  3. a析构,CB_A的强引用计数-1为0,弱引用计数-1=0

  4. OBJ_ACB_A析构,CB_B的弱引用计数-1=0

  5. CB_B析构

http://www.gsyq.cn/news/16926.html

相关文章:

  • 详细介绍:在机器视觉测量和机器视觉定位中,棋盘格标定如何影响精度
  • 题解:P11219 【MX-S4-T3】「yyOI R2」youyou 的序列 II
  • 前端HTML contenteditable 属性使用指南 - 教程
  • C++ list数据删除、list资料访问、list反转链表、list数据排序
  • DP分析黑科技——闫氏DP分析法
  • MUGEN游戏引擎等一系列相关杂谈
  • # 20232313 2025-2026-1 《网络与系统攻防技术》实验一实验报告 - 20232313
  • 完整教程:【无标题】
  • vector使用中的一个小问题
  • 一生一芯学习:PA2:输入输出
  • 深入解析:人工智能-Chain of Thought Prompting(思维链提示,简称CoT)
  • 年龄排序
  • 二分图最大匹配 输出具体方案
  • Success of Europa
  • 2025多校冲刺CSP模拟赛4 总结
  • 多路归并、败者树、置换-选择排序、最佳归并树
  • AI元人文:规则与人文的统一之路
  • 深入解析:SpringBatch+Mysql+hanlp简版智能搜索
  • Cisco vManage漏洞分析:未授权RCE与权限提升完整攻击链
  • 东萍象棋 DhtmlXQ UBB 转 中国象棋云库查询 FEN
  • 十六、【前端强化篇】完善 TestCase 编辑器:支持 API 结构化定义与断言安装
  • 斑马ZT210碳带及纸张安装教程
  • DHCP及DNS
  • C++_基础
  • 2025电位仪厂家最新企业品牌推荐排行榜,纳米粒度及 Zeta 电位仪,Zeta 电位仪公司推荐
  • StarRocks与Apache Iceberg:构建高效湖仓一体的实时分析平台 - 详解
  • MTK oppoR9m Smart Phone flash Tool 提示 ERROR: STATUS_ABORT(0xC0010002)
  • 2025 年酒店一次性用品源头厂家最新推荐排行榜:含牙签牙线筷子套杯盖杯垫杯套外卖筷子印刷房卡套信封用品优质供应商盘点
  • 简单工厂模式 - 实践
  • 1.springmvc基础入门(一) - 详解