【C++】智能指针

    在C++中,我们经常会用到动态开辟内存,需要我们自己维护,在出函数作用域之前,必须将管理的内存释放掉,否则就会造成内存泄漏,即使我们十分小心,但总有可能出错,因此便有了智能指针。

RAII:资源分配即初始化:定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。

1. auto_ptr,auto_ptr的实现机制是资源的转移,在拷贝构造函数和运算符重载函数中将当前对象的指针置为空,以实现资源的转移

template <class T>
class AutoPtr
{
public:
	AutoPtr(T* ptr = NULL)
		: _ptr(ptr)
	{}

	~AutoPtr()
	{
		if (_ptr)
		{
			delete _ptr;
			_ptr = NULL;
		}
	}

	T& operator*()
	{
		return (*_ptr);
	}
	T* operator->()
	{
		return _ptr;
	}
	
	AutoPtr(AutoPtr& ap)
		: _ptr(ap._ptr)
	{
		ap._ptr = NULL;
	}
	AutoPtr& operator=(AutoPtr& ap)
	{
		if (this != &ap)
		{
			if (_ptr)
				delete _ptr;
			_ptr = ap._ptr;
			ap._ptr = NULL;
		}
		return *this;
	}
private:
	T* _ptr;
};

它的缺陷是:当我们用一个对象去构造另一个对象时,原对象由于被置为NULL,则不能再使用了。

我们可以设置增加一个变量,当前对象如果为该资源的拥有者,则可以释放空间,否则,它将只有使用权。

template <class T>
class AutoPtr
{
public:
	AutoPtr(T* ptr = NULL)
		: _ptr(ptr)
		, _owner(true)
	{
		if (NULL == _ptr)
			_owner = false;
	}
	AutoPtr(const AutoPtr& ap)
		: _ptr(ap._ptr)
		, _owner(ap._owner)
	{
		ap._owner = false;
	}
	AutoPtr& operator=(const AutoPtr& ap)
	{
		if (this != &ap)
		{
			if (_ptr)
				delete _ptr;
			_ptr = ap._ptr;
			_owner = ap._owner;
			ap._owner = false;
		}
		return *this;
	}
	~AutoPtr()
	{
		if (_ptr && _owner == true)
		{
			delete _ptr;
			_owner = false;
			_ptr = NULL;
		}
	}
private:
	T* _ptr;
	mutable bool _owner;
};

它的缺陷是:如果我们在一个if的作用域中用对象ap1创建了ap2,那出了作用域,ap2被释放,ap1中的_ptr变成了野指针,无法再使用。因此,C++11建议不要使用auto_ptr。

2. scoped_ptr,这是boost库中的智能指针,它的实现机制是防拷贝,将拷贝构造函数和赋值运算符重载只声明而不定义,并设为私有成员。在C++标准库中unique_ptr与它的实现机制类似。

template<class T>
class ScopedPtr
{
public:
	ScopedPtr(T* ptr = NULL)
		: _ptr(ptr)
	{}
	~ScopedPtr()
	{
		if (_ptr)
		{
			delete _ptr;
			_ptr = NULL;
		}
	}
	T* operator->()
	{
		return _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
private://防拷贝,将声明设为私有而不定义
	ScopedPtr(const ScopedPtr& sp);
	ScopedPtr& operator=(const ScopedPtr sp);
private:
	T* _ptr;
};

3. shared_ptr,它的实现原理类似于string类中的引用计数。拷贝一次,引用计数增加1,当引用计数为0时2,释放空间。

template<class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr = NULL)
		: _ptr(ptr)
		, _pCount(new int(0))
	{
		if (_ptr)
			*_pCount = 1;
	}
	SharedPtr(const SharedPtr& sp)
		: _ptr(sp._ptr)
		, _pCount(sp._pCount)
	{
		(*_pCount)++;
	}
	SharedPtr& operator=(const SharedPtr& sp)
	{
		if (this != &sp)
		{
			if (_pCount && --(*_pCount) == 0)
			{
				delete _ptr;
				delete _pCount;
			}
			_ptr = sp._ptr;
			_pCount = sp._pCount;
			if (*_pCount)
				(*_pCount)++;
		}
		return *this;
	}
	~SharedPtr()
	{
		if (_ptr && --(*_pCount))
		{
			delete _ptr;
			_ptr = NULL;
            delete _pCount;
            _pConut=NULL;
		}
	}
	T* operator->()
	{
		return _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
private:
	T* _ptr;
	int* _pCount;
};

weak_ptr与shared_ptr搭配使用,shared_ptr中存在着循环引用的问题。例如:

template<class T>
struct Node
{
	Node(const T& data)
	: _data(data)
	{
		cout << "Node()" << this << endl;
	}
	T _data;
	weak_ptr<Node<T>> _pNext;
	weak_ptr<Node<T>> _pPre;
	~Node()
	{
		cout << "~Node()" << this << endl;
	}
};

int main()
{
	shared_ptr<Node<int>> sp1(new Node<int>(10));
	shared_ptr<Node<int>> sp2(new Node<int>(20));
	cout << sp1.use_count() << endl;
	cout << sp2.use_count() << endl;
	sp1->_pNext = sp2;
	sp2->_pPre = sp1;
	cout << sp1.use_count() << endl;
	cout << sp2.use_count() << endl;
	return 0;
}

如果只是shared_ptr,由于sp1的next指向了sp2,sp2的pre指向了sp1,因此sp1和sp2的count为2,无法完成析构。当使用了weak_ptr时,引用计数count没有增加,增加的是weak计数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值