【C++ 第二十章】使用 shared_ptr 会出现严重 循环引用 问题?

众所周知,智能指针 shared_ptr 能够允许拷贝行为,是因为其内部使用 引用计数的 方式,使得多个智能指针对象共享同一个资源(如果不了解 shared_ptr ,可以先自己了解学习一下)
而 引用计数 却可能引起 循环引用 的严重问题

代码引入

看下面这段代码:我们构建有一个双向链表节点类,并使用智能指针 shared_ptr 管理,当 main 函数结束时,main 函数栈帧销毁,会调用 shared_ptr 的析构函数,释放对应资源,从而打印语句:"~ListNode"

但是运行下面这段代码,却无运行打印结果??

cpp 复制代码
struct ListNode
{
	int _data;
	shared_ptr<ListNode> _prev;
	shared_ptr<ListNode> _next;

	ListNode(const int& data)
		:_data(data)
	{}
	~ListNode() {
		cout << "~ListNode" << '\n';
	}
};
int main() {
	shared_ptr<ListNode> lt1(new ListNode(10));
	shared_ptr<ListNode> lt2(new ListNode(20));

	lt1->_next = lt2;
	lt2->_prev = lt1;
	return 0;
}

解析原因

这是因为这里出现了 循环引用的问题
循环引用:顾名思义,由于指针的指向,使得某组空间资源释放时,形成了 循环的有向环,使得该组空间都无法完成真正的空间资源释放,最终导致内存泄漏




如何解决循环引用?

出现循环引用的本质是:节点释放后,这块节点空间就由另一个节点的 next 或 prev 指针管理,即没死透(没有真正释放),引用计数还是 1


当引用计数没到 0,这块空间资源都不会被销毁

而这块空间资源永远都被另一个节点中的 next 或 prev 指针管理,是引用计数不会到 0,也就不会销毁该空间


因此, 需要针对 next 和 prev 指针下手

将 next 和 prev 指针 设置成 weak_ptr 类型

该智能指针 weak_ptr 和其他一般的智能指针不同,这个指向空间资源时, 不会增加这块 空间资源 的引用计数,相当于该指针不会作为 某块空间释放的最后守门人, 仅仅只是指向那块空间

关于弱指针 weak_ptr 及用其解决 循环引用的问题

使用 弱指针 weak_ptr 解决 循环引用的问题

该指针是单纯的指向 目标空间资源,而不会增加管理空间的 引用计数,这样就不会导致释放节点时,因为管理权转移引发的 循环引用问题

查看文档,发现 weak_ptr 的构造函数也可以接收 shared_ptr 对象,因此我们可以将上面代码节点类中的 _ next 和 _prev 设置成 weak_ptr 类型

cpp 复制代码
struct ListNode
{
	int _data;
	weak_ptr<ListNode> _prev;
	weak_ptr<ListNode> _next;

	ListNode(const int& data)
		:_data(data)
	{}
	~ListNode() {
		cout << "~ListNode" << '\n';
	}
};
int main() {

	shared_ptr<ListNode> lt1(new ListNode(10));
	shared_ptr<ListNode> lt2(new ListNode(20));


	lt1->_next = lt2;
	lt2->_prev = lt1;


	return 0;
}

这样就有打印结果了


弱指针 weak_ptr 存在的问题:

上面的产生另一个问题:当那块资源释放了,该弱指针就 不就指向一块已经释放的空间,形成 野指针了吗?

弱指针如何知道自己指向的那块资源 是否还存在?

解决方法:弱指针内部也存有 那块资源 的引用计数,通过这个判断

使用 函数 use_count 可以知道引用计数的大小

除了判断 引用计数是否 = 0,还可以直接使用成员函数 expired 判断是否过期

相关推荐
汉克老师1 天前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
智者知已应修善业1 天前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
云泽8081 天前
C++11 核心特性全解:列表初始化、右值引用与移动语义实战
开发语言·c++
AI进化营-智能译站1 天前
ROS2 C++开发系列12-用多态与虚函数构建可扩展的ROS2机器人行为模块
开发语言·c++·ai·机器人
Morwit1 天前
QML组件之间的通信方案(暴露子组件)
c++·qt·职场和发展
qeen871 天前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
图码1 天前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
handler011 天前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
zhouwy1131 天前
Linux进程与线程编程详解
linux·c++
A7bert7771 天前
【YOLOv8pose部署至RDK X5】模型训练→转换bin→Sunrise 5部署
c++·python·深度学习·yolo·目标检测