C++中的智能指针

1.智能指针:智能指针就是智能的、自动化的管理指针所指向的动态资源的释放,并且可以如同指针一样使用。智能指针是RALL(初始化立即获取资源)思想的一种实现,其中初始化利用构造函数,之后将资源保存起来最后让析构函数自动清理。 

2.引入智能指针原因:总的来说,是防止程序执行流的改变、或者人为因素造成的内存泄露问题,在此我们应该知道,影响执行流改变的常见语句有:goto,抛异常,return,break,continue等。

3.智能指针发展:
(1)最早期的auto_ptr
autoptr是一种有着严重缺陷的智能指针,缺陷在于当我们进行拷贝构造时,如果为浅拷贝时,可能会出现同一块空间释放多次的问题,如果为深拷贝也不合理,因为
指针的拷贝,本身就希望指向同一块空间;因此,在拷贝构造这里就出现了大的问题。

关于auto_ptr的模拟实现:

template <class T>
class AutoPtr
{
private:
	T* _ptr;
public:
	AutoPtr(T* ptr)//构造函数
		:_ptr(ptr)
	{}


	~AutoPtr()//析构函数
	{
		cout<<"~AutoPtr()//析构函数"<<endl;
		if(_ptr)
		{
			delete _ptr;
		}
	}

	//1.管理权的转移
	//问题缺陷:当一个智能指针交出对空间的管理权之后,将它置空,不能再对其解引用赋值,废掉
	AutoPtr(AutoPtr<T>& ap)//拷贝构造函数
	{
		_ptr=ap._ptr;
		ap._ptr=NULL;//退出管理
	}

	AutoPtr<T>& operator=(AutoPtr<T>& ap)//赋值操作符的重载
	{
		if(this!=&ap)
		{
			if(_ptr)
			{
				delete _ptr;
			}
			_ptr=ap._ptr;
			ap._ptr=NULL;//退出管理
		}
		return *this;
	}

	T& operator*()//重载*
	{
		return *_ptr;
	}

	T* operator->()//重载->
	{
		return _ptr;
	}

};

解决方案:管理权转移
即再解决对象赋值、拷贝构造的时候,如a=b,先将a的地址空间释放,然后将b.ptr指针赋值给a.ptr,最后将地址空间的管理权交给a.ptr,并且将 b.ptr置为NULL.所以,在此操作
之后,原来的指针将不能再使用,因此其缺点在于,一个智能指针只能指向一块内存,不能有几个指针指向同一块内存空间。

鉴于autoptr的严重缺陷,开发者又自主实现解决以上弊端的智能指针:
(2)scoped_ptr
它所采用的解决方案就是防函数,对拷贝构造函数、赋值运算符的重载声明为私有的 或者保护的,但不去实现它,即实现了防止拷贝,防止赋值的功能

关于scoped_ptr的模拟实现:

template <class T>
class ScopedPtr
{
protected:
	T* _ptr;
public:
	ScopedPtr(T* ptr)//构造函数
		:_ptr(ptr)
	{}

	~ScopedPtr()//析构函数
	{
		if(_ptr)
		{
			delete _ptr;
		}
	}

	T& operator*()//*的重载
	{
		return *_ptr;
	}

	T* operator->()//重载->
	{
		return _ptr;
	}

	//防拷贝的实现,即将拷贝构造、赋值运算符重载函数声明成私有的,并且不定义
private:
	ScopedPtr(const ScopedPtr<T>& sp);
	ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);
};

虽然 表面上解决了auto_ptr的缺陷,但是没有了拷贝、赋值功能,为了不仅可以 屏蔽auot_ptr缺陷,还能拷贝、赋值,我们又提出来了一下:
(3)shared_ptr

它所采用的技术是引用计数思想,在对象构造时记下使用次数,到最后只有一个引用计数的时候再释放,所以依然支持拷贝构造和赋值的操作

关于shared_ptr的模拟实现:

template <class T>
class SharedPtr
{
protected:
	T* _ptr;
	int* _RefCount;
public:
	SharedPtr(T* ptr)//构造函数
		:_ptr(ptr)
		,_RefCount(new int(1))
	{}

	~SharedPtr()//析构函数
	{
		if(--(*_RefCount)==0)
		{
			delete _ptr;
			delete _RefCount;
		}
	}

	SharedPtr(SharedPtr<T>& sp)//拷贝构造函数
	{
		_ptr=sp._ptr;
		_RefCount=sp._RefCount;
		++(*_RefCount);//拷贝构造之后,this多了一个对象指向自己的空间
	}

	SharedPtr<T>& operator=(SharedPtr<T>& sp)//赋值运算符的重载
	{
		if(_ptr!=sp._ptr)
		{
			if(--(*_RefCount)==0)
			{
				delete _ptr;//转变指向之前,先检查自己原来在的那块空间是否只有自己一个人管理
				delete_RefCount;
			}
			_ptr=sp._ptr;
			++(*_RefCount);
		}
		return *this;
	}

	T& operator*()//*的重载
	{
		return *_ptr;
	}

	T* operator->()//重载->
	{
		return _ptr;
	}

};

shared_ptr可以说是比较完美的智能指针了,解决了它之前几个智能指针所存在的问题但是,它的缺陷却在于,它存在着循环引用的问题:

关于循环引用:在使用shared_ptr时,由于节点之间的相互引用使得多个结点指向同一块空间,引用计数不为1,从而在释放空间时,p1等p2释放,p2等p1释放,从而引起的循环引用问题,造成内存泄露。


此时又提出来了以下指针:
(4)weak_ptr
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,像旁观者那样观测资源的使用情况但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。

引入weak_ptr弱引用指针即可解决循环引用问题。weak_ptr不会修改引用计数。

关于weak_pt的模拟实现:

template<class T>
class WeakPtr
{
	WeakPtr()
		:_ptr(NULL)
	{}

	WeakPtr(const SharedPtr<T>& sp)
		:_ptr(sp._ptr)
	{}

	T& operator*()//*的重载
	{
		return *_ptr;
	}

	T* operator->()//重载->
	{
		return _ptr;
	}
private:
	T* _ptr;

};


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值