C++ | 智能指针

智能指针,即智能指针对象,实现了自主的内存回收机制。

  • 智能指针是一个模板,由智能指针实例化出来的对象具有和常规指针相似的行为,但是智能指针能够自动的释放所指向的对象。
  • 对编译器来说,智能指针实际上是一个栈对象,并非指针类型,在栈对象生命周期你即将结束时,智能指针通过析构函数释放由它管理的堆内存。

智能指针的分类:

  • 不带引用计数的智能指针:auto_ptr、unique_ptr、scoped_ptr
  • 带引用计数的智能指针:shared_ptr、weak_ptr

1. auto_ptr

一块堆内存 只要有一个智能指针拥有所有权  

部分源码如下:

template<typename T>
class Auto_Ptr
{
public:
	Auto_Ptr(T* ptr) :mptr(ptr){}
	Auto_Ptr(const Auto_Ptr<T>& rhs)
	{
		mptr = rhs.mptr;
		rhs.Release();
	}
	Auto_Ptr<T>& operator=(const Auto_Ptr<T>& rhs)
	{
		if (this != &rhs)
		{
			delete mptr;//delete NULL;
			mptr = rhs.mptr;
			rhs.Release();
		}
		return *this;
	}
	~Auto_Ptr()
	{
		if (mptr != NULL)
		{
			delete mptr;
		}	
		mptr = NULL;
	}
	T& operator*()
	{
		return *mptr;
	}
	T* operator->()
	{
		return mptr;
	}
private:
	void Release()const
	{
		(T*)mptr = NULL;
	}
	T* mptr;
};

2.带标志位的智能指针

所有权不唯一,释放权唯一。

旧的智能指针有释放权 -> 新的智能指针就有释放权

旧的智能指针无释放权 -> 新的智能指针无释放权

旧的智能指针赋值后肯定没有释放权

即:
        this->flag = rhs.flag;
        rhs.flag = false;

(带标志位的智能指针实际是对auto_ptr的改进)

部分源码如下:

template<typename T>
class SmartPtr
{
public:
	SmartPtr(T* ptr) :mptr(ptr)
	{
		flag = true;
	}
	~SmartPtr()
	{
		if (flag)
		{
			delete mptr;
		}
		mptr = NULL;
	}

	SmartPtr(const SmartPtr<T>& rhs)
	{
		this->mptr = rhs.mptr;

		this->flag = rhs.flag;
		rhs.flag = false;
	}
	SmartPtr<T>& operator=(const SmartPtr<T>& rhs)
	{
		if (this != &rhs)
		{
			if (flag)
			{
				delete mptr;
			}
			mptr = rhs.mptr;
			this->flag = rhs.flag;
			rhs.flag = false;
		}
		return *this;
	}
	T& operator*()
	{
		return *mptr;
	}
	T* operator->()
	{
		return mptr;
	}
private:
	T* mptr;
	mutable bool flag;//是否拥有释放权   true  有   false 无 
};

带标志位的智能指针存在的问题:

由于所有权的转移,可能使内存提前释放,导致其他的智能指针失效。

3.scoped_ptr

一个堆内存只能有一个智能指针来引用。(是最简单的智能指针)

为了防止拷贝带来的问题,scoped_ptr从根本上就不允许拷贝和赋值,即禁止使用拷贝构造函数和赋值运算符的重载函数。

部分源码如下:

template<typename T>
class Scope_Ptr
{
public:
	Scope_Ptr(T* ptr) :mptr(ptr){}
	~Scope_Ptr()
	{
		delete mptr;
	}
	T& operator*()
	{
		return *mptr;
	}
	T* operator->()
	{
		return mptr;
	}
//将拷贝构造函数和赋值运算符的重载函数写在私有成员下,从而“防拷贝,防赋值”
private:
	Scope_Ptr(const Scope_Ptr<T>&);  
	Scope_Ptr<T>& operator=(const Scope_Ptr<T>&);
	T* mptr;
};

4. shared_ptr

强智能指针,允许多个智能指针指向同一个对象。引用计数管理器来管理指向对象的智能指针。

部分源码如下:

//引用计数管理器
class Ref_Management
{
private:
	Ref_Management() :index(0){}
	Ref_Management(const Ref_Management&);
public:
	static Ref_Management* getInstance()
	{
		return &rm;
	}
public:
	void addRef(void* ptr) //增加计数
	{
		int idx = FindAddr(ptr);
		if (idx < 0)
		{
			//node[index].ptr = ptr;
			//node[index++].ref = 1;
			Node tmp(ptr, 1);
			node[index++] = tmp;
		}
		else
		{
			node[idx].ref++;
		}
	}
	void delRef(void* ptr)  //删除计数
	{
		int idx = FindAddr(ptr);
		if (idx < 0)
		{
			throw std::exception("addr is not exist!");
		}
		else
		{
			if (node[idx].ref != 0)
			{
				node[idx].ref--;
			}
		}
	}
	int getRef(void* ptr)  //得到计数
	{
		int idx = FindAddr(ptr);
		if (idx < 0)
		{
			throw std::exception("addr is not exist!");
		}
		return node[idx].ref;
	}
private:
	int FindAddr(void* ptr)  //查找计数
	{
		int rt = -1;
		for (int i = 0; i < 10; i++)
		{
			if (node[i].ptr == ptr)
			{
				rt = i;
				break;
			}
		}
		return rt;
	}

	class Node
	{
	public:
		Node(void* p = NULL, int r = 0) :ptr(p), ref(r){}
	public:
		void* ptr;//堆内存的地址
		int ref;  //对应的引用计数
	};
	Node node[10];
	int index;
	static Ref_Management rm;
};
Ref_Management Ref_Management::rm;

//强智能指针
template<typename T>
class Shared_Ptr
{
public:
	Shared_Ptr(T* ptr = NULL) :mptr(ptr)
	{
		prm->addRef(mptr);
	}
	Shared_Ptr(const Shared_Ptr<T>& rhs) :mptr(rhs.mptr)
	{
		prm->addRef(mptr);
	}
	Shared_Ptr<T>& operator=(const Shared_Ptr<T>& rhs)
	{
		if (this != &rhs)
		{
			prm->delRef(mptr);
			if (prm->getRef(mptr) == 0)
			{
				delete mptr;
			}
			mptr = rhs.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;
	}
	T* getPtr()const
	{
		return mptr;
	}
private:
	T* mptr;
	static Ref_Management* prm;
};

template<typename T>
Ref_Management* Shared_Ptr<T>::prm = Ref_Management::getInstance();

shared_ptr存在的问题:

强智能指针的相互引用,使指针无法释放,导致内存泄漏。

5.weak_ptr

由于强智能指针的相互引用问题,由此引出弱智能指针。

weak_ptr不加引用计数,不能释放内存,不能单独使用,要结合shared_ptr使用

部分源码如下:

template<typename T>
class Weak_Ptr
{
public:
	Weak_Ptr(T* ptr = NULL) :mptr(ptr){}
	Weak_Ptr(const Weak_Ptr<T>& rhs) :mptr(rhs.mptr){}
	Weak_Ptr<T>& operator=(const Shared_Ptr<T>& rhs)  //weak_ptr不能单独使用,要结合shared_ptr使用
	{
		mptr = rhs.getPtr();  //只获得计数,不加计数
		return *this;
	}
	~Weak_Ptr(){}
private:
	T* mptr;
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值