C++ | shared_ptr与weak_ptr


前言

简单介绍shared_ptr与weak_ptr,仿写系统的shared_ptr与weak_ptr,并解决循环引用的问题.


提示:以下是本篇文章正文内容,下面案例可供参考

一、shared_ptr与weak_ptr是什么?

shared_ptr是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting)。一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。
weak_ptr是为配合shared_ptr而引入的一种智能指针。

1.shared_ptr的内存模型

在这里插入图片描述

2.weak_ptr的内存模型

在这里插入图片描述

二、仿写系统的shared_ptr与weak_ptr

1.mdeletor


```cpp
class Mdeletor
{
public:
	Mdeletor() = default;
	void operator()(_Ty* p)const
	{
		if (p != NULL)
		{
			delete p;
		}
		p = NULL;
	}
};

template<typename _Ty>
class Mdeletor<_Ty[]>
{
public:
	Mdeletor() = default;
	void operator()(_Ty* p)const
	{
		if (p != NULL)
		{
			delete[]p;
		}
		p = NULL;
	}
};

2.Ref_con

template<typename _Ty>
class RefCnt
{
protected:
	_Ty* ptr;
	std::atomic_int Uses;
	std::atomic_int Weaks;
public:
	RefCnt(_Ty* p) :ptr(p), Uses(1), Weaks(1) {}
	~RefCnt() {}
	void IncUses()
	{
		Uses += 1;
	}
	void IncWeaks()
	{
		Weaks += 1;
	}
	template<typename _Ty, typename _Dx>
	friend class my_shared_ptr;

	template<typename _Ty>
	friend class my_weak_ptr;
};

3.shared_ptr

代码如下(示例):

template<typename _Ty,typename _Dx= Mdeletor<_Ty>>
class my_shared_ptr
{
private:
	_Ty* Ptr;
	RefCnt<_Ty>* Ref;
	_Dx mdeletor;
public:
	my_shared_ptr(_Ty* p = nullptr) :Ptr(nullptr),Ref(nullptr)
	{
		if (p != nullptr)
		{
			Ptr = p;
			Ref = new RefCnt<_Ty>(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& other):Ptr(other.Ptr),Ref(other.Ref)//拷贝构造
	{
		if (Ptr != NULL)
		{
			Ref->IncUses();
		}
	}
	my_shared_ptr(my_shared_ptr&& other) :Ptr(other.Ptr), Ref(other.Ref)//移动构造
	{
		other.Ptr = NULL;
		other.Ref = NULL;
	}

	my_shared_ptr& operator=(const my_shared_ptr& other)//赋值
	{
		if (this == &other || Ptr == other.Ptr)  return *this;//自赋值,直接返回本身
		
		if (Ptr != NULL && --Ref->Uses == 0)//被赋值的智能指针对象拥有资源,
		{                                   //且该对象仅被该智能指针拥有
			mdeletor(Ptr);//释放该对象
			if (--Ref->Weaks == 0)//当弱引用计数为零时
			{
				delete Ref;//析构引用计数对象
				Ref = NULL;
			}
		}

		Ptr = other.Ptr;
		Ref = other.Ref;
		if (Ptr != NULL)
		{
			Ref->IncUses();
		}
		return *this;
	}

	my_shared_ptr& operator=(my_shared_ptr&& other)//移动赋值
	{
		if (this == &other)  return *this;
		if (Ptr == other.Ptr && Ptr != NULL)//当两个智能指针使用同一个对象时,且该对象不为空
		{
			other.Ptr = NULL;//去掉other的使用权
			other.Ref = NULL;
			Ref->Uses -= 1;//强引用计数-1

			return *this;
		}

		if (Ptr != NULL && --Ref->Uses == 0)
		{
			mdeletor(Ptr);
			if (--Ref->Weaks == 0)
			{
				delete Ref;
				Ref = NULL;
			}
		}
		Ptr = other.Ptr;
		Ref = other.Ref;

		other.Ptr = NULL;
		other.Ref = NULL;

		return *this;
	}

	~my_shared_ptr()
	{
		if (Ptr != NULL && --Ref->Uses == 0)
		{
			mdeletor(Ptr);
			if (--Ref->Weaks == 0)
			{
				delete Ref;
			}
		}
		Ref = NULL;
	}

	_Ty* get()const
	{
		return Ptr;
	}

	_Ty& operator*()
	{
		return *get();
	}

	_Ty* operator->()
	{
		return get();
	}

	size_t use_count()const
	{
		if (Ref == NULL)  return 0;
		return Ref->Uses;
	}

	void swap(my_shared_ptr& other)
	{
		std::swap(Ptr, other.Ptr);
		std::swap(Ref, other.Ref);
	}

	operator bool()const
	{
		return Ptr != NULL;
	}
	template<typename _Ty>
	friend class my_weak_ptr;
};

4.weak_ptr

代码如下(示例):

template<typename _Ty>
class my_weak_ptr
{
private:
	RefCnt<_Ty>* wRef;
public:
	my_weak_ptr() :wRef(NULL) {}
	my_weak_ptr(const my_shared_ptr<_Ty>& other) :wRef(other.Ref)//共享指针构造
	{
		if (wRef!=NULL)
		{
			wRef->IncWeaks();
		}
	}

	my_weak_ptr(const my_weak_ptr& other) :wRef(other.wRef)//拷贝构造
	{
		if (wRef != NULL)
		{
			wRef->IncWeaks();
		}
	}

	my_weak_ptr(my_weak_ptr&& other) :wRef(other.wRef)//移动构造
	{
		other.wRef = NULL;
	}

	my_weak_ptr& operator=(const my_weak_ptr& other)
	{
		if (this == &other||wRef=other.wRef)  return *this;//自赋值或者是两个指针指向同一个对象

		if (this != NULL && --wRef->Weaks == 0)//是否自己独占对象
		{
			delete wRef;
		}

		wRef = other.wRef;
		if (wRef != NULL)
		{
			wRef->IncUses();
		}

		return *this;
	}
	my_weak_ptr& operator=(my_weak_ptr&& other)
	{
		//1 判断是否自赋值
		if (this == &other)  return *this;

		//2 判断是否是指向同一个对象的两个指针相互赋值
		if (wRef == other.wRef && wRef != NULL)//如果是
		{
			other.wRef = NULL;
			wRef->Weaks -= 1;
			return *this;
		}

		//3 两个指向不同对象的指针赋值
		if (this != NULL && --wRef->Weaks == 0)//是否自己独占对象
		{
			delete wRef;//如果独有
		}

		wRef = other.wRef;
		other.wRef = NULL;
		
		return *this;
	}
	my_weak_ptr& operator=(const my_shared_ptr<_Ty>& other)//共享智能指针给弱指针赋值
	{
		if (wRef == other.Ref)  return *this;

		if (wRef != NULL && --wRef->Uses == 0)
		{
			delete wRef;
		}
		wRef = other.Ref;

		if (wRef != NULL)
		{
			wRef->IncWeaks();
		}

		return *this;
	}
	my_weak_ptr& operator=( my_shared_ptr<_Ty>&& other) = delete;
	~my_weak_ptr()
	{
		if (wRef != NULL && --wRef->Weaks == 0)
		{
			delete wRef;
			
		}
		wRef = NULL;
	}
	bool expired()const//判断被引用的对象是否删除,若删除则返回真
	{
		return wRef->Uses == 0;
	}
	my_shared_ptr<_Ty> lock()const
	{
		my_shared_ptr<_Ty>tmp;
		tmp.Ptr = wRef->ptr;
		tmp.Ref = wRef;
		tmp.Ref->IncUses();
		return tmp;

	}
};

该处使用的url网络请求的数据。


三、解决循环引用问题

在这里插入图片描述

四、总结

weak_ptr一般需要与shared_ptr联合使用,且若要使用weak_ptr时需要用lock()函数返回一个shared_ptr的对象再进行使用。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值