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;
	};
相关推荐
010米粉0102 分钟前
Qt Cmake之路(一):Cmake变量语法
开发语言·qt·cmake
前端小L5 分钟前
贪心算法专题(二):波动中的智慧——只取极值「摆动序列」
数据结构·算法·贪心算法
aini_lovee5 分钟前
基于Jousselme距离改进D-S证据理论matlab实现
开发语言·算法·matlab
再睡一夏就好9 分钟前
深入解析Linux页表:从虚拟地址到物理内存的映射艺术
linux·运维·服务器·c语言·c++·页表·缺页异常
颜*鸣&空9 分钟前
Qt Creator快速搭建项目
开发语言·qt
道剑剑非道13 分钟前
Qt【使用libmodbus库】
开发语言·数据库·qt
白兰地空瓶15 分钟前
你以为树只是画图?不——它是算法面试的“隐形主角”
前端·javascript·算法
csbysj202018 分钟前
PHP 函数
开发语言
好易学·数据结构25 分钟前
可视化图解算法74:最小花费爬楼梯
数据结构·算法·leetcode·动态规划·力扣
Starry_hello world36 分钟前
C++ 线程 (3)
c++