shared_ptr隐患之重复释放堆对象

原以为智能指针可以完全保证对堆对象的正确引用和释放,但智能指针不是万能的。以shared_ptr为例,以下几种使用情况会使得代码重复释放堆对象。

1.滥用原始指针构造shared_ptr

#include <iostream>
#include <memory>

class A {};
using Ptr = std::shared_ptr<A>;

int main()
{
	A *ps = new A();
	Ptr p1(ps);
	Ptr p2(p1);
	Ptr p3 = p2;
	Ptr p4;
	p4 = p3;
	
	Ptr p5(ps);

	std::cout << p1.use_count() << std::endl;	
	std::cout << p2.use_count() << std::endl;	
	std::cout << p3.use_count() << std::endl;	
	std::cout << p4.use_count() << std::endl;	
	std::cout << p5.use_count() << std::endl;	

	return 0;
}

运行结果如下:

在这里插入图片描述

可以看到,在使用拷贝构造或赋值运算符=的时候,shared_ptr会共享并更新控制块。而当使用原始指针构造一个新的shared_ptr时,会创建并初始化一个新的控制块。

因此在程序最后,当shared_ptr要析构自己指向的堆对象的时候,会重复释放内存,从而引起运行时错误。

构造shared_ptr时,如果其指向的对象已被别的shared_ptr所指,请使用拷贝构造或赋值运算初始化新指针。

2.类内包含指向自身的shared_ptr

#include <iostream>
#include <memory>

class A;
using SPtr = std::shared_ptr<A>;
using WPtr = std::weak_ptr<A>;

class A {
public:
	A() : sptr(this), wptr(sptr)
	{
		std::cout << "in construct :" << std::endl;
		std::cout << sptr.use_count() << std::endl;
		std::cout << this << " " << sptr << " " << wptr.lock() << std::endl;
	}
private:
	SPtr sptr;
	WPtr wptr;
};

int main()
{
	A *p = new A();
	SPtr ptr(p);	
	std::cout << "in main :" << std::endl;
	std::cout << ptr.use_count() << std::endl;

	return 0;
}

运行结果如下:
在这里插入图片描述

原因和上面类似,一个堆对象两个shared_ptr控制块管理,最终导致重复释放内存。

如果main函数是这样的,也会运行出错。原因是当对象被delete释放的时候,对象中的shared_ptr也被释放,此时它所指向的对象(this)又会被释放一次。

int main()
{
	A *p = new A();
	std::cout << p << std::endl;
	delete p;

	return 0;
}

在这里插入图片描述

请诸君别使用这种奇葩的用法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值