C++11:shared_ptr循环引用问题

一、shared_ptr的弊端

cpp 复制代码
struct Listnode
{
	int _val;
	std::shared_ptr<Listnode> _prev;
	std::shared_ptr<Listnode> _next;
	Listnode(int val )
		:_val(val)
		,_prev(nullptr)
		,_next(nullptr)
	{}
	~Listnode()
	{
		cout << "~Listnode()" << endl;
	}
};
int main()
{
	std::shared_ptr<Listnode> n1(new Listnode(20));
	std::shared_ptr<Listnode> n2(new Listnode(10));

	n1->_next = n2; 
	n2->_prev = n1;

	return 0;
}

如上的情况就出现了循环引用,两个对象相互掣肘。

  1. node1和node2两个智能指针对象指向两个节点,引用计数变成1,我们不需要手动delete。
  2. node1的_next指向node2,node2的_prev指向node1,引用计数变成2。
  3. node1和node2析构,引用计数减到1,但是_next还指向下一个节点。但是_prev还指向上一个节点。
  4. 也就是说_next析构了,node2就释放了。
  5. 也就是说_prev析构了,node1就释放了。
  6. 但是_next属于node的成员,node1释放了,_next才会析构,而node1由_prev管理,_prev属于node2成员,所以这就叫循环引用,谁也不会释放。
    展开来讲:
    两个对象的引用计数都变为2,当要进行析构时就陷入了循环引用。

1、左边节点要想析构就得等右边的_prev去调用析构。

2、右边节点被delete时去调用_prev.

3、而右边节点被析构需要左边节点的_next去调用析构

4、左边节点被delete时去调用_prev

5、左边节点要想析构就得等右边的_prev去调用析构。

到这里就以及死循环了。

二、weak

它的特点就是不增加引用计数,专门用于shared_ptr出现循环引用的情况。

cpp 复制代码
struct Listnode
{
	int _val;
	std::weak_ptr<Listnode> _prev;
	std::weak_ptr<Listnode> _next;
	Listnode(int val )
		:_val(val)
	{}
	~Listnode()
	{
		cout << "~Listnode()" << endl;
	}
};
int main()
{
	std::shared_ptr<Listnode> n1(new Listnode(20));
	std::shared_ptr<Listnode> n2(new Listnode(10));

	n1->_next = n2; 
	n2->_prev = n1;

	return 0;
}

2.1模拟实现

cpp 复制代码
struct Listnode
{
	int _val;
	gaz::weak_ptr<Listnode> _prev;
	gaz::weak_ptr<Listnode> _next;
	Listnode(int val )
		:_val(val)
	{}
	~Listnode()
	{
		cout << "~Listnode()" << endl;
	}
};
int main()
{
	gaz::shared_ptr<Listnode> n1(new Listnode(20));
	gaz::shared_ptr<Listnode> n2(new Listnode(10));

	n1->_next = n2; 
	n2->_prev = n1;

	return 0;
}
cpp 复制代码
template<class T>
	class weak_ptr
	{
	public:
		//RALL
		weak_ptr()
			:_ptr(nullptr)
		{}
		weak_ptr(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
		}
		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
相关推荐
CoovallyAIHub2 小时前
语音AI Agent编排框架!Pipecat斩获10K+ Star,60+集成开箱即用,亚秒级对话延迟接近真人反应速度!
深度学习·算法·计算机视觉
木心月转码ing4 小时前
Hot100-Day14-T33搜索旋转排序数组
算法
会员源码网6 小时前
内存泄漏(如未关闭流、缓存无限增长)
算法
颜酱7 小时前
从0到1实现LFU缓存:思路拆解+代码落地
javascript·后端·算法
颜酱8 小时前
从0到1实现LRU缓存:思路拆解+代码落地
javascript·后端·算法
CoovallyAIHub1 天前
Moonshine:比 Whisper 快 100 倍的端侧语音识别神器,Star 6.6K!
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
速度暴涨10倍、成本暴降6倍!Mercury 2用扩散取代自回归,重新定义LLM推理速度
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
实时视觉AI智能体框架来了!Vision Agents 狂揽7K Star,延迟低至30ms,YOLO+Gemini实时联动!
算法·架构·github
CoovallyAIHub1 天前
开源:YOLO最强对手?D-FINE目标检测与实例分割框架深度解析
人工智能·算法·github