智能指针(三)—— shared_ptr 循环引用问题(智能指针什么情况下存在内存泄漏)

shared_ptr 作为智能指针,可以满足大多数场景,对于一些特殊情况,比如当两个对象同时使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄露。


         目录

1、循环引用案例分析

(1) 案例介绍

(2) 原因分析

2、weak_ptr 解决循环引用 


1、循环引用案例分析

(1) 案例介绍

我们通过实际案例来了解循环引用,ListNode结构体的定义如下:

struct ListNode
{
    int _data;
    shared_ptr<ListNode> _next;

    ~ListNode() { cout << "~ListNode()" << endl; }
}

我们使用这个结构体做了如下操作:

int main()
{
	shared_ptr<ListNode> n1(new ListNode);
	shared_ptr<ListNode> n2(new ListNode);

	n1.get()->_next = n2;			// 代表深蓝色的线所做的事(n1结点的下一个指向n2)
	n2.get()->_next = n1;			// 代表浅蓝色的线所做的事(n2结点的下一个指向n1)

	return 0;
}

我们运行程序会发现,析构函数没有被调用,按理来说,出了作用域,两个对象的引用计数都自减到了0,此时会调用析构函数释放资源,但是实际上并未调用。两个智能指针相互管理造成了对方的资源无法释放,这造成了“循环引用”。

(2) 原因分析

首先,程序释放 n2,此时 n2 的引用计数自减

 然后释放 n1,n1的引用计数自减

到此,程序结束,此时两者的引用计数依然没有自减到0,所以不会调用析构函数。实际上只要双方有一方的智能指针不去多管闲事,如 n1的_next 不去指向 n2,这种事情就不会发生。 

2、weak_ptr 解决循环引用 

weak_ptr 不是常规意义的指针,没有接收一个原生指针的构造函数,他的出现是为了解决shared_ptr 的循环引用问题。

为了解决上述循环引用的问题,我们只需要把ListNode 内部的shared_ptr 改为 weak_ptr 即可。

struct ListNode
{
	int _data;
	weak_ptr<ListNode> _next;        //原本是shared_ptr,现在改为weak_ptr

	~ListNode() { cout << "~ListNode()" << endl; }
};

原理是 weak_ptr 在参与资源管理时,不会增加引用计数,但是会检测到所管理的对象是否已经被释放,从而避免非法访问。简单来说,即便是让一个weak_ptr 去指向其他智能指针,别人都没把你当指针看待,不会增加引用计数。

修改以后的测试结果如下:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值