c++智能指针会引起错误的两种情况

1返回管理this的 share_ptr

struct Test
{
	shared_ptr<Test> getSharedPtr()
	{
		return shared_ptr<Test>(this);
	}

	~Test()
	{
		cout << "析构函数" << endl;
	}
};

int main()
{
	shared_ptr<Test> sp1(new Test);
	cout << "引用计数 " << sp1.use_count() << endl;
	shared_ptr<Test> sp2 = sp1->getSharedPtr();
	cout << "引用计数: " << sp1.use_count() << endl;
	return 0;
}
引用计数: 1
引用计数: 1
析构函数
析构函数

通过输出的结果可以看到一个对象被析构了两次,其原因是这样的:在这个例子中使用同一个指针 this 构造了两个智能指针对象 sp1 和 sp2,这二者之间是没有任何关系的,因为 sp2 并不是通过 sp1 初始化得到的实例对象。在离开作用域之后 this 将被构造的两个智能指针各自析构,导致重复析构的错误。

#include <iostream>
#include <memory>
using namespace std;

struct Test : public enable_shared_from_this<Test>
{
	shared_ptr<Test> getSharedPtr()
	{
		return shared_from_this();
	}
	~Test()
	{
		cout << "析构函数" << endl;
	}
};

int main()
{
	shared_ptr<Test> sp1(new Test);
	cout << "引用个数: " << sp1.use_count() << endl;
	shared_ptr<Test> sp2 = sp1;
	cout << "引用个数: " << sp1.use_count() << endl;
	return 0;
}

引用个数: 1
引用个数: 2
析构函数

2循环引用问题

class A;
class B;

class A
{
public:
	shared_ptr<B> bptr;
	~A()
	{
		cout << "A的析构函数" << endl;
	}
};

class B
{
public:
	shared_ptr<A> aptr;
	~B()
	{
		cout << "b的析构函数." << endl;
	}
};

void testPtr()
{
	shared_ptr<A> ap(new A);
	shared_ptr<B> bp(new B);
	cout << "A 的 引用计数: " << ap.use_count() << endl;
	cout << "B 的 引用计数: " << bp.use_count() << endl;

	ap->bptr = bp;
	bp->aptr = ap;
	cout << "A 的 引用计数: " << ap.use_count() << endl;
	cout << "B 的 引用计数: " << bp.use_count() << endl;
}

int main()
{
	testPtr();
	return 0;
}
A 的 引用计数 : 1
B 的 引用计数 : 1
A 的 引用计数 : 2
B 的 引用计数 : 2

共享智能指针 ap、bp 对 A、B 实例对象的引用计数变为 2,在共享智能指针离开作用域之后引用计数只能减为1,这种情况下不会去删除智能指针管理的内存,导致类 A、B 的实例对象不能被析构,最终造成内存泄露。

最开始我们的ap和bp各个指向了A和B,但是我们将A里面的shared_ptr指向了B后bp对应的内存被再次引用了一次,导致bp对应的引用计数++,ap也是同理。

04f9ddbe9abae10ed7353a5ef0d50e02.png

当我们的主函数结束时,只会析构ap与bp,但是因为ap与bp对应的引用计数为2,就不会调用析构函数,从而造成内存泄漏。

通过使用 weak_ptr 可以解决这个问题,只需要将类 A 或者 B 的任意一个成员改为 weak_ptr.

class A;
class B;

class A
{
public:
	weak_ptr<B> bptr;
	~A()
	{
		cout << "A 的 析构函数" << endl;
	}
};

class B
{
public:
	shared_ptr<A> aptr;
	~B()
	{
		cout << "B 的 析构函数" << endl;
	}
};

void testPtr()
{
	shared_ptr<A> ap(new A);
	shared_ptr<B> bp(new B);
	cout << "A 的 引用计数: " << ap.use_count() << endl;
	cout << "B 的 引用计数: " << bp.use_count() << endl;

	ap->bptr = bp;
	bp->aptr = ap;
	cout << "A  的 引用计数: " << ap.use_count() << endl;
	cout << "B  的 引用计数: " << bp.use_count() << endl;
}

int main()
{
	testPtr();
	return 0;
}

A 的 引用计数: 1
B 的 引用计数: 1
A  的 引用计数: 2
B  的 引用计数: 1
B 的 析构函数
A 的 析构函数

上面程序中,在对类 A 成员赋值时 ap->bptr = bp; 由于 bptr 是 weak_ptr 类型,这个赋值操作并不会增加引用计数,所以 bp 的引用计数仍然为 1,在离开作用域之后 bp 的引用计数减为 0,类 B 的实例对象被析构。

在类 B 的实例对象被析构的时候,内部的 aptr 也被析构,其对 A 对象的管理解除,内存的引用计数减为 1,当共享智能指针 ap 离开作用域之后,对 A 对象的管理也解除了,内存的引用计数减为 0,类 A 的实例对象被析构。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值