C++ weak_ptr弱引用智能指针

weak_ptr

  • 循环引用
  • 共享智能指针的助手
  • 弱引用智能指针的实现
  • 循环引用问题解决

weak_ptr这个指针天生一副小弟的模样,也是在C++11的时候引入的标准库,它的出现完全是为了弥补它老大shared_ptr天生有缺陷的问题。

相比于上一代的智能指针auto_ptr来说,新进老大shared_ptr可以说近乎完美,但是通过引用计数实现的它,虽然解决了指针独占的问题,但也引来了引用成环的问题,这种问题靠它自己是没办法解决的,所以在C++11的时候将shared_ptr和weak_ptr一起引入了标准库,用来解决循环引用的问题。

循环引用

class Child;
class Parent
{
public:
	shared_ptr<Child> child;
	Parent() { cout << "Parent" << endl; }
	~Parent() { cout << "~Parent" << endl; }
	void hi() { cout << "Hello" << endl; }
};
class Child
{
public:
	shared_ptr<Parent> parent;
	Child() { cout << "Child" << endl; }
	~Child() { cout << "~Child" << endl; }
};
void fun()
{
	shared_ptr<Parent> p = make_shared<Parent>();
	shared_ptr<Child> c = make_shared<Child>();

	p->child = c;
	c->parent = p;
	c->parent->hi();
}
int main()
{
	fun();
	return 0;
}

C++ weak_ptr弱引用智能指针_第1张图片
此时两个智能指针的引用计数都为2,但是当函数生命周期结束,引用计数结果为1,那么会出现只有构造函数没有析构函数
C++ weak_ptr弱引用智能指针_第2张图片
这里就需要引入弱引用智能指针

class Child;
class Parent
{
public:
	//shared_ptr child;
	std::weak_ptr<Child> child;
	Parent() { cout << "Parent" << endl; }
	~Parent() { cout << "~Parent" << endl; }
	void hi() { cout << "Hello" << endl; }
};
class Child
{
public:
	//shared_ptr parent;
	std::weak_ptr<Parent> parent;
	Child() { cout << "Child" << endl; }
	~Child() { cout << "~Child" << endl; }
};
void fun()
{
	shared_ptr<Parent> p = make_shared<Parent>();
	shared_ptr<Child> c = make_shared<Child>();

	p->child = c;
	c->parent = p;
	//c->parent->hi();
}
int main()
{
	fun();
	return 0;
}

C++ weak_ptr弱引用智能指针_第3张图片

共享智能指针的助手

在RefCnt中引入了,_weaks的计数,用来帮助解决共享智能指针的缺陷

weak_ptr的原理

weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。不论是否有weak_ptr指向,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。从这个角度看,weak_ptr更像是shared_ptr的一个助手而不是智能指针。

template<class _Ty>
class MyDeletor //可接受一切类型方案
{
public:
	MyDeletor() = default;//默认构造函数
	void operator()(_Ty* ptr) const
	{
		if (ptr != nullptr)
		{
			delete ptr;
		}
	}
};
template<class _Ty>
class MyDeletor<_Ty[]> //部分特化
{
public:
	MyDeletor() = default;
	void operator()(_Ty* ptr)const
	{
		if (ptr != nullptr)
		{
			delete[] ptr;
		}
	}
};

template<class _Ty>
class RefCnt
{
public:
	_Ty* _Ptr;				//obj
	std::atomic_int _Uses;  //shared_ptr
	std::atomic_int _Weaks; //weak_ptr

public:
	RefCnt(_Ty* p):_Ptr(p),_Uses(1),_Weaks(1)
	{}
	~RefCnt()
	{}
	void _Incref()
	{
		_Uses += 1;
	}
	void _Incwref()
	{
		_Weaks += 1;
	}
};

template<class _Ty> class my_weak_ptr;

template<class _Ty,class _Dx = MyDeletor<_Ty>>
class my_shared_ptr
{
private:
	_Ty* _Ptr;
	RefCnt<_Ty>* _Rep;
	_Dx _mDeletor;
public:
	my_shared_ptr(_Ty* p = nullptr) :_Ptr(nullptr), _Rep(nullptr)
	{
		if (p != NULL)
		{
			_Ptr = p;
			_Rep = new RefCnt<_Ty>(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& _Y):_Ptr(_Y._Ptr),_Rep(_Y._Rep)
	{
		if (_Rep != nullptr)
		{
			_Rep->_Incref();//引用计数增一
		}
	}
	my_shared_ptr(my_shared_ptr&& other)
	{
		other.swap(*this); //资源交换
	}
	my_shared_ptr& operator=(const my_shared_ptr& r)
	{
		if (this == &r || this->_Ptr == r._Ptr) return *this;
		if (_Ptr != nullptr && --_Rep->_Uses == 0)
		{
			_mDeletor(_Ptr); //删除旧资源
			if (--_Rep->_Weaks == 0)
			{
				delete _Rep; //删除计数器
			}
		}
		_Ptr = r._Ptr;
		_Rep = r._Rep;
		if (_Ptr != nullptr)
		{
			_Rep->_Incref();//共享自加
		}
		return *this;
	}
	my_shared_ptr& operator=(my_shared_ptr&& other)
	{
		if (this == &other) return *this;
		if (this->_Ptr != nullptr && other._Ptr != nullptr && this->_Ptr == other._Ptr)
		{
			this->_Rep->_Uses -= 1;
			other._Ptr = nullptr;
			other._Rep = nullptr;
			return *this;
		}
		if (_Ptr != nullptr && --_Rep->_Uses == 0)
		{
			_mDeletor(_Ptr);
			if (--_Rep->_Weaks == 0)
			{
				delete _Rep; 
			}
		}
		_Ptr = other._Ptr;
		_Rep = other._Rep;
		other._Ptr == nullptr;
		other._Rep == nullptr;
		return *this;
	}
	~my_shared_ptr()
	{
		if (_Rep != nullptr&& --_Rep->_Uses == 0)//uses 持有对象的生存期到期
		{
			_mDeletor(_Ptr); //删除对象
			if (_Rep->_Weaks == 0) 
			{
				delete _Rep; //删除计数器结构
			}
		}
		_Ptr = nullptr;
		_Rep = nullptr;
	}
	_Ty* get()const
	{
		return _Ptr;
	}
	_Ty& operator*()const
	{
		return *get();
	}
	_Ty* operator->()const
	{
		return get();
	}
	size_t use_count()const
	{
		if (_Rep == nullptr) return 0;
		return _Rep->_Uses;
	}
	void swap(my_shared_ptr& r)
	{
		std::swap(_Ptr, r._Ptr);
		std::swap(_Rep, r._Rep);
	}
	operator bool() const
	{
		return _Ptr != nullptr;
	}
};

C++ weak_ptr弱引用智能指针_第4张图片
在上面代码中,通过新引入的_weaks;当op1进行析构,调动共享性智能指针的析构函数,调动删除器将 Object 的对象进行销毁,但是由于_weaks的计数不为1,所以不会对RefCnt引用计数器进行删除,即使 Object 资源已经释放;接着析构wp,当弱引用计数_weaks为零后才会对 RefCnt 进行释放

弱引用智能指针的实现

template<class _Ty> 
class my_weak_ptr
{
private:
	RefCnt<_Ty>* _Rep;
public:
	my_weak_ptr():_Rep(nullptr) //不会新建RefCnt
	{}
	my_weak_ptr(const my_shared_ptr<_Ty>& other):_Rep(other._Rep)
	{
		if (_Rep != nullptr)
		{
			_Rep->_Incwref(); //weaks 自加
		}
	}
	my_weak_ptr(const my_weak_ptr& other) :_Rep(other._Rep)
	{
		if (_Rep != nullptr)
		{
			_Rep->_Incwref();
		}
	}
	my_weak_ptr(const my_weak_ptr&& other):_Rep(other._Rep)
	{
		other._Rep = nullptr;
	}
	my_weak_ptr& operator=(const my_weak_ptr& other)
	{
		if (this == &other && this->_Rep == other._Rep) return *this;
		if (_Rep != nullptr && --_Rep->_Weaks == 0) //前置自减!!!
		{
			delete _Rep;
		}
		_Rep = other._Rep;
		if (_Rep != nullptr)
		{
			_Rep->_Incwref();
		}
		return *this;
	}
	my_weak_ptr& operator=(my_weak_ptr&& other)
	{
		if (this == &other) return *this;
		if (this->_Rep != nullptr && other._Rep != nullptr && this->_Rep == other._Rep)
		{
			other->_Rep->_Weaks -= 1;
			other._Rep == nullptr; //删除other资源
			return *this;
		}
		if (_Rep != nullptr && --_Rep->_Weaks == 0)
		{
			delete this._Rep;
		}
		this._Rep = other._Rep;
		other._Rep = nullptr;
	}
	my_weak_ptr& operator=(const my_shared_ptr<_Ty>& other)//强指针给弱引用赋值
	{
		if (_Rep != nullptr && --_Rep->_Weaks == 0)
		{
			delete _Rep;
		}
		_Rep = other._Rep;
		if (_Rep != nullptr)
		{
			_Rep->_Incwref();
		}
		return *this;
	}//不能将强指针移动赋值给弱引用
	~my_weak_ptr()
	{
		if (_Rep != nullptr && --_Rep->_Weaks == 0) //弱引用计数为0		{
		{
			delete _Rep; //删除RefCnt
		}
		_Rep == nullptr;
	}
	bool expired() const //检查被引用的对象是否删除
	{
		return this->_Rep->_Uses == 0;
	}
	my_shared_ptr<_Ty> lock()const
	{
		my_shared_ptr<_Ty> _Ret;
		_Ret._Ptr = this->_Rep->_Ptr;
		_Ret._Rep = this->_Rep;
		_Ret._Rep->_Incref();
		return _Ret;
	}
};

我们不需要担心,当弱引用智能指针析构删除 RefCnt 的时候会造成共享智能指针的资源丢失,因为弱引用智能指针不会新建 RefCnt 并且在共享智能指针中会对weaks首先赋值为1,并且弱引用指针没有权限去释放计数器所指的资源

循环引用问题解决

class Child;
class Parent
{
public:
	my_weak_ptr<Child> c;
public:
	Parent()
	{
		cout << "parent" << endl;
	}
	~Parent()
	{
		cout << "~parent" << endl;
	}
	void hi()const
	{
		cout << "hello parent" << endl;
	}
};
class Child
{
public:
	my_weak_ptr<Parent> p;
	Child()
	{
		cout << "Child" << endl;
	}
	~Child()
	{
		cout << "~Child" << endl;
	}
};
void fun()
{
	my_shared_ptr<Parent> parent(new Parent());
	my_shared_ptr<Child> child(new Child());
	parent->c = child;
	child->p = parent;
	child->p.lock()->hi();
}

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

C++ weak_ptr弱引用智能指针_第5张图片

  1. 首先析构 shared_ptr child 智能指针,_Usrs 强引用计数自减后为0,继而将其所指的Child对象进行析构
  2. shared_ptr parent智能指针,_Weaks 弱引用计数随着上一步孩子对象析构,引用计数变为1
  3. 接着析构shared_ptr parent,_Usrs自减后为0,将其所指Parent对象进行析构,并且由于_Weaks 弱引用计数也自减得0,将其 RefCnt 进行析构
  4. 随着上一步Parent对象析构,原本shared_ptr child所指 RefCnt 中的_Weaks 也变为0,将child智能指针的 RefCnt 也进行析构

你可能感兴趣的:(C++,c++)