一步一步写STL:定制stl::auto_ptr

原创文章    转载请注明出处http://blog.csdn.net/effective_coder

           

          欢迎来到内存这块雷区,在对内存分配器进一步讨论之前我觉得有必要先讨论一下STL中的auto_ptr,我也加了很多STL的讨论社区以及很多群,长久以来发现了一个很大的问题,太多的人反映出不敢用auto_ptr,原因是好多好多未定义行为,用到最后自己都摸不着头脑了,其实如果来分析一下他的来龙去脉,也不是那么难!为此我采取分析STL的auto_ptr和boost里面的shared_ptr两种不同风格的智能指针,希望更具全面性!(注:在0X标准中auto_ptr已经取消了,被更高级的指针替代,不过这里还是讨论一下)

 

在我另一篇文章中对auto_ptr有一些基本的介绍auto_ptr简介 对于怎么用智能指针 不属于本文范畴  看过那篇文章对于auto_ptr也应该了解了!

这里多说一些,在我们的程序中经常出现

ClassA *ptr=new ClassA;

```````````````````中间步骤`````````

Delete ptr;

这样的风格,中间步骤发生异常或者是忘记加delete,或者是delete之后忘记置0 ,造成内存泄露和使用错误,针对这个问题如何解决,在C++ primer上面为我们提供了了两种解决方案,

1:设置拥有权的转移

2:使用引用计数的方式

我记得大一的时候看到这两点,完全看不懂是什么意思,呵呵,现在终于可以一笑置之了!

所以针对这个两个解决方案,出现了两种风格的智能指针,STL中的auto_ptr属于拥有权转移指针,boost中的shared_ptr属于引用计数型(boost里面的智能指针有6个,这里只是其中一个)


针对auto_ptr:

对于设置拥有权限转移的指针,我们需要做的就是在复制和赋值的时候重定向指针,使得他们不会出现多个指针指向同一个对象,出现指针悬空的现象,在C++ primer 591页有一个针对auto_ptr的表格,列出了所有成员函数以及相应的说明,其实我觉得就算不懂STL源码,在C++ primer看到591页的情况下,写出这个模拟的auto_ptr不是什么难事,先看我的源码 :

template<typename Ty>
class Auto_ptr
{
private:
	Ty *ap;
public:

	explicit Auto_ptr (Ty * ptr = 0)throw()
		:ap(ptr)
	{//构造函数,指定explicit不能隐式使用
	}

	Auto_ptr (Auto_ptr &r)throw()
		:ap( r.release() )
	{ //复制构造,注意看参数
	}

	template<typename _other>
	Auto_ptr (Auto_ptr<_other> &other )throw()
		:ap (other.release() )
	{//重载的模版复制函数,作用稍后细说
	}

	Auto_ptr& operator= (Auto_ptr &other)throw()
	{//赋值操作符,同样转移了拥有权
		reset( other.release() );
		return *this;
	}

	template<typename Y>
	Auto_ptr& operator= (Auto_ptr<Y> &other)throw()
	{//重载,同复制构造函数
		reset( other.release() );
		return *this;
	}

	//重置函数,带默认参数
	void reset( Ty* ptr = 0 )throw(){
		if( ptr != ap )
		{
			delete ap;
			ap = ptr;
		}
	}
	//该函数释放掉自己的对象,并返回
	Ty* release ()throw(){
		Ty* temp( ap );
		ap = 0;
		return temp;
	}

	//这个接口标准里面没有,是我自己加的,我觉得有必要转型
	operator bool()throw(){
		return ap;
	}

	~Auto_ptr()throw(){
		//析构函数
		delete ap;
	}

	Ty* get() const throw(){
		return ap;
	}

	Ty& operator* ()throw(){
		return *ap;
	}

	Ty* operator-> ()throw(){
		return ap;
	}

};


 

代码不多,也很好懂,这里我特别说明一下几点:

1:构造函数一定要加explicit关键字,因为auto_ptr只能显式的构造(参见auto_ptr标准)

2:复制构造函数的参数千万不能加const,因为加了const就成了锁定指针了,拥有权再也转移不出去了,何谈复制(同赋值操作符)

3:为什么要重载一个模版函数,难道指针之间可以互相复制或赋值吗?其实我们这里这样写主要是为了基类和派生类的转换,这样可以不影响多态性的发挥!

4:接下来的几个函数见名知意,很简单,而且我们的Auto_ptr没有++ --操作符,这个根据需要自己定制,当标准的智能指针不满足我们需要可以自己随便改啊(只要你喜欢)

5:这点很重要,现在这个类还不完整,没有const的功能,即锁定拥有权不转移的功能,为此参考了Greg Colvin的一份实例,他的做法有点高级过头了

template <typename T>
struct ref_auto_ptr
{
	T* p;
	ref_auto_ptr(T *r = 0)throw()
		:p(r){
	//仅只有成员和构造
	}
}

首先在我们的类之前添加这么一个类 然后在Auto_ptr中添加以下成员函数:

Auto_ptr(ref_auto_ptr<Ty> &rh)throw()
		:ap(rh.p)
	{
	}

	Auto_ptr& operator =(ref_auto_ptr<Ty> &rh)throw()
	{
		reset(rh.p);
		return *this;
	}

	template<typename T>
	operator ref_auto_ptr<T> ()throw()
	{
		return ref_auto_ptr( release() );
	}

	template<typename T>
	operator Auto_ptr<T> ()throw()
	{
		return Auto_ptr<T>( release() );
	}

说实话我还不是很明白这个转型代码,就算明白点也感觉说不出来,他把右值转化为左值,这样子非const的可以转化,但是const就不能转化,这个怎么解释清楚点,希望留言指点!

到现在我们基本的Auto_ptr功能完备实现了,测试一下:

#include "auto_ptr.h"

int _tmain(int argc, _TCHAR* argv[])
{
	Auto_ptr<int> ptr( new int(1024) );
	Auto_ptr<int> ptr2;
	ptr2 = ptr;
	cout<< *ptr2 <<" "<<endl;     //正常转移 输出结果1024

	const Auto_ptr<int> ptr3( new int(1024) );
	Auto_ptr<int> ptr4;
	ptr4 = ptr3;                //编译期错误“没有找到接受“const Auto_ptr<Ty>”类型的右操作数的运算符(或没有可接受的转换)”
	
	system("pause");
	return 0;
}


下一节 :定制智能指针 shared_ptr

求助:希望懂的人给我解释下,上面那个const转型是如何把右值转成了左值,谢谢!

 

 

 

 

 

 

 

 

你可能感兴趣的:(一步一步写STL:定制stl::auto_ptr)