C++ auto_ptr的简单模拟实现

一、auto_ptr的简单模拟实现

关于auto_ptr的缺陷我在之前的博客中就已经说明。在这篇博客中我们从它的底层来更进一步阐述。

在学习中,对某一个类进行简单的模拟,一般情况下,我们只需要模拟实现四个函数,分别是:构造函数、析构函数、拷贝构造函数以及赋值运算符重载。但是对于一个指针来说,它还要加上*运算符重载->运算符重载

	template<class T>
	class Auto_ptr
	{
	public:

		//构造函数
		Auto_ptr(T* _ptr=NULL)
		{
			ptr = _ptr;
		}

		//析构函数
		~Auto_ptr()
		{
			if (ptr != NULL)
			{
				delete ptr;
			}
		}

		//拷贝构造函数
		Auto_ptr(const Auto_ptr<T>& ap)
		{
			ptr = ap.ptr;
			ap.ptr = NULL;
		}

		//赋值运算符重载
		Auto_ptr<T>& operator=(Auto_ptr<T>& ap)
		{
			if (this != &ap)
			{
				if (ptr != NULL)
					delete ptr;

				ptr = ap.ptr;
				ap.ptr = NULL;

			}

			return *this;
		}

		T& operator*()
		{
			return *ptr;
		}

		T* operator->()
		{
			return ptr;
		}

	private:
		T * ptr;
	};

二、对auto_ptr的缺陷的分析

从赋值运算符重载函数和拷贝构造函数来看,他们所使用的的是一个浅拷贝,所以如果auto_ptr对象之间出现了赋值和拷贝的情况,那么就会出现,多个指针指向了同一个空间的情况,在对象声明周期结束的时候,会出现同一块空间被多次释放的情况,所以为了改变这种情况,auto_ptr使用的是一个管理权转移的思想,所以在发生拷贝构造或者是赋值时,将原来的auto_ptr置为空,这样就解决了二次释放的问题。但是这样也有一个缺陷,那就是在用原来的auto_ptr访问数据时,会出现内存错误,因为此时的auto_ptr是一个NULL,用一个NULL去访问数据显然是C++不允许的。

三、对赋值运算符重载函数的一些说明

(1)赋值运算符重载
对于一个赋值运算符重载,我们有以下四点要注意的地方(注意这不仅仅是对于以上代码而言,对于所有的赋值运算符重载都适用):

  1. 检查返回值类型是否是该类类型的引用,并且返回值也是自身引用(即*this)。
    因为只有返回一个引用类型,那么才能做到连续赋值(即s1=s2=s3),否则如果函数返回的不是一个引用,那么在进行连续赋值的时候,编译器就会报错。

  2. 检查函数的形参是否是const引用类型。
    因为如果传入的参数不是引用,而是一个实例的话,那么在实参对形参结合的这个过程中会调用拷贝构造函数。而如果是一个引用就会避免这种无端的销毁,从而提高效率。之所以声明为const,是因为在赋值运算符中,我们可以保证不会对对象进行修改。

  3. 检查在赋值之前是否释放掉自身已有内存
    如果我们忘记在赋值之前释放掉自身已有内存,那么就会出现内存泄漏。

  4. 检查是否判断自我赋值

    因为在赋值运算符重载函数中,我们首先要对自身对象进行释放,然后才开始赋值。如果没有判断自我赋值,那么当是同一个对象进行赋值时,释放掉自身对象,其实也是将传入参数的内存也释放掉了,因此就找不到要赋值的内容了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章