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;
	};
相关推荐
星夜离尘5616 小时前
MATLAB 离散数据分箱:半开区间、末端点与计数、加权和、平均
算法·matlab
Pniubi16 小时前
力扣76.最小覆盖子串
算法·leetcode·职场和发展
地平线开发者16 小时前
征程6|用 hrt\_model\_exec 看清 YOLOv5x 的输入、原始输出和后处理
人工智能·算法
csdn_aspnet17 小时前
C++ 3个有序点的方向(Orientation of 3 ordered points)
c++·算法
Felven17 小时前
C. Brr Brrr Patapim
c语言·开发语言
赤生云电竞17 小时前
GPU算力共享平台架构实践:任务分发与资源隔离的关键配置
算法·架构·gpu算力
小七在进步18 小时前
string的使用(2)
c++
路溪非溪19 小时前
python标准库使用总结
开发语言·python
青少儿编程课堂19 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:折半搜索优化子集枚举(Meet in the Middle)解析
c++·python·算法·bfs·信息学竞赛
SomeOtherTime20 小时前
Rust 面向对象介绍(AI回答)
开发语言·python·rust