C++之智能指针

本文介绍了C++中的智能指针,包括auto_ptr的特性及其在C++11中被摒弃的原因,接着详细讲述了unique_ptr的所有权唯一原则以及不支持拷贝和赋值的特点。接着讨论了shared_ptr的引用计数机制以及存在的相互引用问题,并提出了weak_ptr作为解决方案,解释了weak_ptr的弱引用特性和如何与shared_ptr配合使用以避免资源泄露。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++98引入了auto_ptr
auto_ptr:
**特点:**管理权限唯一,控制权限唯一<所有权唯一>
只有一个指针对象进行管理,剩下的都会失效.数据无法共享
不能在容器中保存auto_ptr,也不能从函数中返回auto_ptr.
在这里插入图片描述
上图所示是错误的,因为所有权是唯一的.
所以在C++11摒弃了auot_ptr:要避免因为潜在的内存问题导致程序崩溃.
auto_ptr的简单实现:

template<typename T>
class Auto_Ptr
{
public:
	Auto_Ptr(T* ptr)//构造函数
		:mptr(ptr)//初始化
	{}
	Auto_Ptr(Auto_Ptr<T>& rhs)//拷贝构造函数
	{
		mptr = rhs.Release();
	}
	Auto_Ptr<T>& operator=(Auto_Ptr<T>& rhs)//赋值运算符重载
	//如果形参和this指针指向同一块内存,系统就会崩溃
	{
		if (this != &rhs)
		{
			delete mptr;
			mptr = rhs.Release();
		}
		return *this;
	}
	~Auto_Ptr()
	{
		delete mptr;
		mptr = NULL;
	}
	T& operator*()
	{
		return *mptr;
	}
	T* operator->()
	{
		return mptr;
	}
private:
	T* Release()
	{
		T* ptmp = mptr;
		mptr = NULL;
		return ptmp;
	}
	T* mptr;
};

C++11智能指针:
unique_ptr:
**特点:**1.所有权唯一
2.不支持普通的拷贝或赋值操作.
在这里插入图片描述
**shared_ptr:
特点:**1.所有权不唯一,允许多个智能指针指向同一个对象
2.引用计数减为0 释放内存
存在问题:相互引用的问题

std::shared_ptr<A> pa(new A());
	std::shared_ptr<B> pb(new B());
	pa->spa = pb;
	pb->spb = pa;

上面的代码有相互引用的问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放.
在这里插入图片描述
shared_ptr的实现:

class Ref_Mem//引用计数管理器
{
public:
	static Ref_Mem* getInstance()
	{
		return &rm;
	}
	int getRef(void* ptr)//获得引用计数器
	{
		if (ptr == NULL)
		{
			return -1;
			//throw std::exception("pointer is NULL");
		}
		for (int i = 0; i < cursize; i++)
		{
			if (ptr == ref_count[i].addr)
			{
				return ref_count[i].count;
			}
		}
		return -1;
	}
	void addRef(void* ptr)//添加引用计数
	{
		if (ptr == NULL)
			return;
		int index = find(ptr);
		if (index != -1)
		{
			ref_count[index].count++;
		}
		else
		{
			ref_count[cursize].addr = ptr;
			ref_count[cursize++].count = 1;
		}
	}
	void delRef(void* ptr)//减少引用计数
	{
		if (ptr == NULL)
			return;
		int index = find(ptr);
		if (index == -1)
		{
			throw std::exception("pointer is error!");
		}
		if (getRef(ptr) != 0)
		{
			ref_count[index].count--;
		}
	}
private:
	Ref_Mem()
	{
		cursize = 0;
	}
	int find(void* ptr)
	{
		for (int i = 0; i < cursize; i++)
		{
			if (ptr == ref_count[i].addr)
			{
				return i;
			}
		}
		return -1;
	}
	typedef struct Ref
	{
		void* addr;
		int count;
	}Ref;
	Ref ref_count[10];
	int cursize;
	static Ref_Mem rm;
};
Ref_Mem Ref_Mem::rm;
template<typename T>
class Shared_Ptr
{
public:
	Shared_Ptr(T* ptr = NULL)
	{
		mptr = ptr;
		prm->addRef(mptr);
	}
	Shared_Ptr(Shared_Ptr<T>& _Right)
	{
		mptr = _Right.mptr;
		prm->addRef(mptr);
	}
	Shared_Ptr<T>& operator=(Shared_Ptr<T>& _Right)
	{
		if (this != &_Right)
		{
			prm->delRef(mptr);
			if (prm->getRef(mptr) == 0)
			{
				delete mptr;
			}
			mptr = _Right.mptr;
			prm->addRef(mptr);
		}
		return *this;
	}
	~Shared_Ptr()
	{
		prm->delRef(mptr);
		if (prm->getRef(mptr) == 0)
		{
			delete mptr;
		}
		mptr = NULL;
	}
	T& operator*()
	{
		return *mptr;
	}
	T* operator->()
	{
		return mptr;
	}
private:
	T* mptr;
	static Ref_Mem* prm;
};
template<typename T>
Ref_Mem* Shared_Ptr<T>::prm = Ref_Mem::getInstance();

为了解决shared_ptr相互引用的问题,引入了weak_ptr
特点:
1.不加引用计数
2.没有释放权限(不能单独使用)
3.shared_ptr和weak_ptr一般结合着来使用
它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。

	std::shared_ptr<A> pa(new A());
	std::weak_ptr<B> pb(new B());
	pa->spa = pb;
	pb->spb = pa;

上述代码解决了相互引用带来的死锁问题.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值