C++浅谈之智能指针shared_ptr循环引用
- 软件开发
- 2025-08-20 09:30:02

C++ 浅谈之智能指针 shared_ptr 循环引用
HELLO,各位博友好,我是阿呆 🙈🙈🙈
这里是 C++ 浅谈系列,收录在专栏 C++ 语言中 😜😜😜
本系列阿呆将记录一些 C++ 语言重要的语法特性 🏃🏃🏃
OK,兄弟们,废话不多直接开冲 🌞🌞🌞
一 🏠 概述智能指针是什么:
智能指针是⼀个 RAII 类模型,⽤于动态分配内存,其设计思想是将基本类型指针封装为(模板)类对象指针,并在离开作⽤域时调⽤析构函数,使⽤ delete 删除指针所指向的内存空间 🐌🐌🐌
注:RAII 机制是一种对资源申请、释放操作的封装
shared_ptr 智能指针:
对于 shared_ptr ,实现共享式拥有的概念,即多个智能指针可以指向相同的对象,该对象及相关资源会在其所指对象不再使⽤之后,自动释放与对象相关的资源 🐳🐳🐳
shared_ptr 实现原理:
构造函数中计数初始化为 1拷⻉构造函数中计数值加 1赋值运算符中,左边的对象引⽤计数减 1,右边的对象引⽤计数加 1析构函数中引⽤计数减 1在赋值运算符和析构函数中,如果减 1 后为 0 ,则调⽤ delete 释放对象 ✌ ✌ ✌ 二 🏠 核心 什么是循环引用两个类对象相互使用 shared_ptr 指向对方,从而造成内存泄漏 👊👊👊
先补充一个小知识 C++ 类成员的构造和析构顺序
创建对象时 🎅🎅🎅
① 若有父类,执行父类构造函数
② 类非静态数据成员,按声明顺序创建
③ 执行该类构造函数
销毁对象时 👳👳👳
① 调用该类析构函数
② 销毁数据成员,与创建时顺序相反
③ 若有父类,调用父类析构函数
再看如下所示循环引用代码 👇👇👇
a1 引用计数减 1,b1 引用计数也减 1#include <iostream> #include <memory> using namespace std; class A; class B; class A { public: std::shared_ptr<B> bptr; ~A() { cout << "A is deleted" << endl; } //析构后, 才释放成员 bptr }; class B { public: std::shared_ptr<A> aptr; ~B() { cout << "A is deleted" << endl; } //析构后, 才释放成员 aptr }; int main() { { std::shared_ptr<A> a1(new A); //A 对象引用计数为 1 std::shared_ptr<B> b1(new B); //B 对象引用计数为 1 a1->bptr = b1; //A 对象引用计数加 1 b1->aptr = a1; //B 对象引用计数加 1 //此时 A 和 B 对象的引用计数均为 2 } //离开作用域后 //由于 a1 和 b1 的生命周期结束, 所以 A 对象引用计数减 1, B 对象引用计数也减 1 //但 bptr 和 aptr , 引用计数为 1 return 0; }当 A 析构函数被调用时,才会释放成员变量 bptr,即当且仅当 A 对象的引用计数为 0
当 B 析构函数被调用时,才会释放成员变量 aptr,即当且仅当 B 对象的引用计数为 0
综上,两个类对象相互使用 shared_ptr 指向对方造成了类死锁现象,导致内存泄漏 🌻🌻🌻
如何解决循环引用方式一
A 对象和 B 对象都成功析构,不会造成内存泄漏 👦👦👦
{ std::shared_ptr<A> a1(new A); //A 对象引用计数为 1 std::shared_ptr<B> b1(new B); //B 对象引用计数为 1 a1->bptr = b1; //A 对象引用计数加 1 //b1->aptr = a1; //此时 A 对象的引用计数为 2 //B 对象的引用计数为 1 } //离开作用域后, 由于 a1 和 b1 的生命周期结束, 所以 A 对象引用计数减 1, B 对象引用计数也减 1 //此时 A 对象的引用计数为 1 //B 对象的引用计数为 0 (B 析构函数被调用), 释放成员变量 aptr //此时 A 对象的引用计数为 0 (A 析构函数被调用)方式二
A 对象和 B 对象都成功析构,不会造成内存泄漏 👨🚀👨🚀👨🚀
{ std::shared_ptr<A> a1(new A); //A 对象引用计数为 1 std::shared_ptr<B> b1(new B); //B 对象引用计数为 1 a1->bptr = b1; //A 对象引用计数加 1 b1->aptr = a1; //B 对象引用计数加 1 //此时 A 和 B 对象的引用计数均为 2 b1->aptr.reset(); //手动释放成员变量 //此时 A 对象的引用计数为 2 //B 对象的引用计数为 1 } //离开作用域后, 由于 a1 和 b1 的生命周期结束, 所以 A 对象引用计数减 1, B 对象引用计数也减 1 //此时 A 对象的引用计数为 1 //B 对象的引用计数为 0 (B 析构函数被调用), 释放成员变量 aptr //此时 A 对象的引用计数为 0 (A 析构函数被调用)方式三
那么有没有更优秀的解法呢 ?当然有,那就是 weak_ptr 🐌🐌🐌
weak_ptr:弱引用,不能控制对象的生命周期,且不是独立的智能指针,依赖于 shared_ptr 存在
int main() { shared_ptr<int> sp(new int(10)); cout<< sp.use_count() <<endl; //输出1 weak_ptr<int> wp1 = sp; weak_ptr<int> wp2 = sp; cout<< sp.use_count() <<endl; //输出1 }将上例任一类成员从 shared_ptr 改为 weak_ptr,即可解决循环引用问题 🐳🐳🐳
三 🏠 结语身处于这个浮躁的社会,却有耐心看到这里,你一定是个很厉害的人吧 👍👍👍
各位博友觉得文章有帮助的话,别忘了点赞 + 关注哦,你们的鼓励就是我最大的动力
博主还会不断更新更优质的内容,加油吧!技术人! 💪💪💪
C++浅谈之智能指针shared_ptr循环引用由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++浅谈之智能指针shared_ptr循环引用”