C++新特性22_智能指针循环引用问题原理解析(循环引用问题原理:互相仅仅将引用计数从2减为1,都在等待对方将自己的引用结束掉,使得引用计数为0;解决方法:让其中一个的引用计数,设为1)

前面讲过了强指针和弱指针为什么会存在以及循环引用如何解决?但是可能还是比较模糊,为什么会出现循环引用,最终导致二者的指针都不能得到释放呢?
本篇就将前面的内容用到循环引用中来。

1.循环引用导致的问题原理

先看一段之前自己写的只能指针的程序:

// TestC11.cpp : 定义控制台应用程序的入口点。
//

#include <iostream>
#include <cstring>

using namespace std;

//智能指针:
// 1. 用起来像指针
// 2. 会自己对资源进行释放

class CStudent
{
public:
	CStudent() {}

	void test() {
		cout << "CStudent" << endl;
		m_nSex = 1;
	}

private:
	char* m_pszBuf;
	int   m_nSex;
};


template<typename T>
class CSmartPtr;

template<typename T>
class CRefCount
{
	friend class CSmartPtr<T>;
public:
	CRefCount(T* pStu) {
		m_pObj = pStu;
		m_nCount = 1;
	}

	~CRefCount() {
		delete m_pObj;
		m_pObj = NULL;
	}

	void AddRef() {
		m_nCount++;
	}

	void Release() {
		if (--m_nCount == 0) {
			//这么写就表示自己一定要是一个堆对象
			delete this;
		}
	}

private:
	T* m_pObj;
	int       m_nCount;
};

template<typename T>
class CSmartPtr
{
public:

	CSmartPtr()
	{
		m_pRef = NULL;
	}

	CSmartPtr(T* pStu)
	{
		m_pRef = new CRefCount<T>(pStu);
	}

	~CSmartPtr()
	{
		if (m_pRef != NULL) {
			m_pRef->Release();
		}
	}

	CSmartPtr(CSmartPtr& obj)
	{
		m_pRef = obj.m_pRef;
		m_pRef->AddRef();
	}

	CSmartPtr& operator=(CSmartPtr& obj)
	{
		if (m_pRef == obj.m_pRef) {
			return *this;
		}

		if (m_pRef != NULL)
		{
			m_pRef->Release();
		}

		m_pRef = obj.m_pRef;
		m_pRef->AddRef();

		return *this;
	}

	void test2()
	{
		cout << "test2" << endl;
	}

	T* operator->()
	{
		return m_pRef->m_pObj;
	}

	T** operator&()
	{
		return &m_pRef->m_pObj;
	}

	T& operator*()
	{
		return *m_pRef->m_pObj;
	}

	operator T*()
	{
		return m_pRef->m_pObj;
	}

private:
	CRefCount<T>* m_pRef;
};

class B;

class A
{

public:
	A() {}
	CSmartPtr<B> m_b; //A类中包含B的智能指针
};

class B
{

public:
	B() {}
	CSmartPtr<A> m_a; //B类中包含A的智能指针
};


int main(int argc, char* argv[])
{
	{
		CSmartPtr<A> a = new A;
		CSmartPtr<B> b = new B; //b引用计数+1
		a->m_b = b; //b赋值给a中的m_b,b引用计数+1=2
		b->m_a = a;
	}

	return 0;
}

在未出作用域之前,a,b已经被引用两次
在这里插入图片描述
出了作用域之后,引用计数仍然是1,说明资源未被成功释放,这与之前的share_ptr是类似效果。
在这里插入图片描述
那么如果没有循环引用,资源是否可以得到有效释放呢?

int main(int argc, char* argv[])
{
	{
		CSmartPtr<A> a = new A;
		CSmartPtr<B> b = new B;
		//a->m_b = b;
		//b->m_a = a;
	}

	return 0;
}

没有循环引用情况下,引用计数为1
在这里插入图片描述
出块作用域之后,资源得到释放,引用计数为0
在这里插入图片描述

2.循环引用导致无法正常释放的原因

  • 互相仅仅将引用计数从2减为1,都在等待对方将自己的引用结束掉,使得引用计数为0,才能使用Release()中的delete this结束自己
  • 两个人都持有对方的指针,都不愿释放,最终都不释放,类似于死锁状态
    (两个人打架,互相撕扯着对方的头发,一个不撒手,另一个绝对不会撒手)

3. 怎么解决循环引用不能释放的问题呢?

让其中一个的引用计数,设为1,这样在析构时计数为1的就会先释放,这样另一个循环引用的也会变为1(一方撒手,另一方也就撒手)
这就是weak_ptr的作用!

4.学习视频地址:智能指针循环引用问题原理解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值