c++ 智能指针笔记1 auto_ptr unique_ptr scoped_ptr

1、auto_ptr

 智能指针形如其名,智能(可以自主删除在堆上开辟的空间),指针(可以和普通指针一样,可以由 * , -> 操作)。在内部,其实就是一个对象。
 auto_ptr时最早的智能指针,最早是c98中的vc版本,再到vs版本,在还有boost库里的各种智能指针。我们首先介绍他的基本用法,然后进行模拟。
 我们要注意,从C ++ 11开始不推荐使用此类智能指针。推荐使用 unique_ptr,是一种具有类似功能的新设施,但具有更高的安全性(无伪造副本分配),增加的功能(删除器)和对数组的支持。

void main()
{

	int  *tmp = new int(100);
	auto_ptr<int> ap(tmp); //智能指针ap接管tmp,ap其实是一个对象,智能体现在对象由析构方法,不要用户析构
	cout << *ap << endl;  //输出100
	auto_ptr<string> ap1(new string("hello world!"));
	cout << ap1->size() << endl;

	ap1.reset(new string("good "));  //重新设置ap1管理的对象
	cout << ap1->size() << endl;
	ap1.release();  //释放指向的对象的空间(vs c++11)/释放指向对象的所有权(vc c++98)
	auto_ptr<string>ap2 (new string ("bad"));
	ap1 = ap2;
	cout << *ap1 << endl;

}

 注意我们不能同时构造两个指向一个地址的智能指针,这样会导致程序崩溃,原因很简单,地址释放了两次。

void main()
{
	string* s = new string("1234");
	auto_ptr<string> ap1(s);
	//auto_ptr<string> ap2(s);  //程序出错
	//以下不会出错,因为再将ap1赋值给ap2时,ap1的所有权变为false
	auto_ptr<string> ap2(s);
	ap2 = ap1;
}

 但仍有一个问题是,*ap1还是=1234,说明auto_ptr还存在藕断丝连的问题。

1.1、模拟实现,vc版本

 成员包括两个,一个时要指向的指针,一个是所有权_Owns(当_Owns==true),说明智能指针有效,相反,无效。

template<class _Ty>
class my_auto_ptr
{
public:
	my_auto_ptr(_Ty *_P = 0) : _Owns(_P != 0), _Ptr(_P)//当_P != 0时,_Owns=1,_Ptr=_P
	{}
	my_auto_ptr(const my_auto_ptr<_Ty> &_Y) : _Owns(_Y._Owns), _Ptr(_Y.release())
	{}
	my_auto_ptr<_Ty>& operator =(const  my_auto_ptr<_Ty>& _Y)
	{
		if (this != &_Y)
		{
		  if (_Ptr != _Y.get())  //
			{
				if (_Owns)  //当原来由空间时,要删除原有空间
					delete _Ptr;
				_Owns = _Y._Owns;
			}
			else if (_Y._Owns)   //如果_Y._Owns为flase,则不改变_Owns的所有权
				_Owns = true;
			_Ptr = _Y.release();//删除原有的管理权,赋值给_Ptr
		}
		return (*this);
	}
	~my_auto_ptr()
	{
		if (_Owns)
			delete _Ptr;
	}
public:
	_Ty& operator*()const
	{
		return *_Ptr;
	}
	_Ty* operator->()const
	{
		return _Ptr;
	}
public:
	_Ty* release()const  //删除智能指针,将管理权变为false
	{
		//_Owns = false; 不行,是常方法,必须进行强制类型转换   或者使用 mutable关键字
		//*((bool*)&_Owns) = false;  //要么直接将const bool类型强转为bool类型
		((my_auto_ptr<_Ty>*)this)->_Owns = false;  //要么直接将const (my_auto_ptr<_Ty>*)this类型强转为(my_auto_ptr<_Ty>*) this类型         强制转换 忽略类型
		return _Ptr;
	}
	_Ty* get()const
	{
		return _Ptr;
	}
private:
	bool _Owns;//管理权
	_Ty *_Ptr;  //指向这块地址的指针
};

 唯一注意的是,在赋值运算符重载时,其实和我们常说的深拷贝的思想差不多,但是因为还有一个变量, _Owns 所有权,所以还需要增加对_Owns的判断。

1.2、模拟实现,vs版本

 vs版本改进了vc版本,不存在藕断丝连的问题,只有一个私有成员。

template<class _Ty>
class my_auto_ptr
{
	typedef my_auto_ptr<_Ty> _Myt;
public:
	my_auto_ptr(_Ty *_Ptr = 0) : _Myptr(_Ptr)
	{}
	auto_ptr(_Myt& _Right) : _Myptr(_Right.release())
	{}
	_Myt& operator=(_Myt& _Right)
	{
		reset(_Right.release());//这一步相当于做了两件事,1、释放智能指针_Right 2、reset(_Right._Myptr)  将_Right._Myptr赋值给_Myptr
		return (*this);
	}
	~my_auto_ptr()
	{
		delete _Myptr;
	}
public:
	_Ty& operator*() const
	{
		return (*get());
	}
	_Ty *release()
	{
		_Ty *_Tmp = _Myptr;
		_Myptr = 0;
		return (_Tmp);
	}
	_Ty *get() const
	{
		return (_Myptr);
	}
	void reset(_Ty *_Ptr = 0)
	{
		if (_Ptr != _Myptr)
			delete _Myptr;
		_Myptr = _Ptr;
	}
private:
	_Ty *_Myptr;   //
};

2、unique_ptr

 unique_ptr是c++11推荐使用的,与auto_ptr相比,unique_ptr不允许拷贝构造和赋值,将这两个成员方法变为私有。

void main()
{
	string* s = new string ("1234");
	unique_ptr<string> up(s);
	cout << up->size() << endl;
	//不允许拷贝构造和赋值
	//unique_ptr<string> up2(up);
	//unique_ptr<string> up3;
	//up3 = up2;    
}

 unique_ptr也可以对数组进行操作,

#include <iostream>
#include <memory>
int main () {
	std::unique_ptr<int[]> foo (new int[5]);
    for (int i=0; i<5; ++i) foo[i] = i;
    for (int i=0; i<5; ++i) std::cout << foo[i] << ' ';
    std::cout << '\n';
    return 0;
}

 unique_ptr自己定制删除器,


template <class T>
class state_deleter {  // a deleter class with state
public:
	
	void operator()(T* p) {
		std::cout << "[deleted[] #" << "]\n";
		delete[] p;
	}
};

void main()
{
	unique_ptr<int, state_deleter<int>> sp2(new int[3], del);
}

2.1 模拟实现

 这里,我们主要参考scoped_ptr来实现。

template<class T>
class My_unique_ptr
{
private:
	T * px;
	My_unique_ptr(My_unique_ptr const &);
	My_unique_ptr & operator=(My_unique_ptr const &);
	typedef My_unique_ptr<T> this_type;
	void operator==(My_unique_ptr const&) const;
	void operator!=(My_unique_ptr const&) const;
public:
	typedef T element_type;
	explicit My_unique_ptr(T * p = 0) : px(p) // never throws
	{  }
	~My_unique_ptr() // never throws
	{
		//boost::checked_delete(px);
		delete px;
	}
	void reset(T * p = 0) // never throws
	{
		this_type(p).swap(*this);
	}
	T & operator*() const // never throws
	{
		return *px;
	}
	T * operator->() const // never throws
	{
		return px;
	}
	T * get() const // never throws
	{
		return px;
	}
	void swap(My_unique_ptr & b) // never throws
	{
		T * tmp = b.px;
		b.px = px;
		px = tmp;
	}
};

在scoped_ptr源码中,其实还有以下两个函数,用于检查类型的完整度,因为c++11允许对不完整类型的delete,但如果class的析构函数有特定数据操作,或者具有自定义的operator delete成员函数,那么删除指针的操作将导致不确定后果。

template<class T> 
	inline void checked_delete(T * x)
	{
		//用于类型完整度的检查
		typedef char type_must_be_complete[sizeof(T) ? 1 : -1];
		(void) sizeof(type_must_be_complete);
		delete x;
	}
	template<class T> 
	inline void checked_array_delete(T * x)
	{
		typedef char type_must_be_complete[sizeof(T) ? 1 : -1];
		(void) sizeof(type_must_be_complete);
		
		delete[] x;
	}

3、scoped_ptr

 unique_ptr其实就是scoped_ptr,scoped_ptr先出现在boost库种,随后被c++11采用,改名为unique_ptr。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值