智能指针(auto_ptr的实现)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaodu655/article/details/85780663

旧版的auto_ptr
既然要控制资源的转移,我们可以多定义一个成员对象_owner来标识该成员对象的资源管理权,在调用构造函数创建对象时赋予其资源管理权,即_owner置为true,在调用拷贝构造函数、赋值运算符的时候将其管理权释放,即_owner置为false,就起到了资源管理权的转移

#include<iostream>
using namespace std;
template<class T>
class Autoptr
{
public:
        Autoptr<T>(T*ptr = NULL)
               :_ptr(ptr)
               , _symbol(true)

        {}
        Autoptr<T>(const Autoptr<T>&a)
               :_ptr(a._ptr)
               , _symbol(true)
        {
               a._symbol = false;
        }
        Autoptr<T>&operator=(const Autoptr<T>&a)
        {
               if (this != &a)
               {
                       delete this->_ptr;
                       _ptr = a._ptr;
                       _symbol = ture;
                       a._symbol = false;
               }
               return *this;
        }
        T&operator*()//解引用操作符重载
        {
               return *(this->_ptr);
        }
        T&operator*()const//const型解引用操作符重载
        {
               return  *(this->_ptr);
        }
        T*operator->()//取地址操作符重载
        {
               return this->_ptr;
        }
        T*operator->()const//const型取地址操作符重载
        {
               return this->_ptr;
        }
        ~Autoptr<T>()
        {
               if (_ptr)
               {
                       delete _ptr;
                       _ptr = NULL;
                       _symbol = false;
               }
        }
private:
        T* _ptr;
        mutable bool _symbol;//在const修饰的成员函数中要对类的某个数据成员进行修改,该数据成员定义声明必须加mutale关键字。
};
int main()
{
        Autoptr<int>p1(new int);//
        int i = 1;
        if (i == 1)
        {
               Autoptr<int>p2(p1);
        }
        *p1 = 10;
        system("pause");
        return 0;
}

原因是:p2出了if作用域会释放,将自己的空间释放,当再次为p1赋值将导致寻址失败,而导致程序崩溃。

新版的auto_ptr的实现:
继承旧版的auto_ptr实现的思想,将symbol去掉,在使用拷贝构造、赋值运算符重载后直接将原对象置空。

//新版
template<class T>
class Auto_ptr
{
public:
        Auto_ptr(T*ptr=NULL)
               : _ptr(ptr)
        {}
        Auto_ptr( /*const*/ Auto_ptr<T>&a)
               :_ptr(a._ptr)
        {
               a._ptr = NULL;
        }
        Auto_ptr<T>&operator=(const Auto_ptr<T>&a)
        {
               if (this != &a)
               {
                       delete _ptr;
                       _ptr = a._ptr;
                       a._ptr = NULL;
               }
               return *this;
        }
        T&operator*()//解引用操作
        {
               return *(this->_ptr);
        }
        T&operator*()const//解引用操作
        {
               return *(this->_ptr);
        }
        T*operator->()//取地址操作
        {
               return this->_ptr;
        }
        T*operator->()const//const取地址操作
        {
               return this->_ptr;
        }
        ~Auto_ptr<T>()
        {
               if (_ptr)
               {
                       delete _ptr;
                       _ptr = NULL;
               }
        }
private:
        T* _ptr;
};
int main()
{
        Auto_ptr<int> p(new int(1));
        Auto_ptr<int> p1(p);
        Auto_ptr<int> p2 = p1;
        *p= 10;//这样就会报错误。
        system("pause");
        return 0;
}

这样的结果虽出乎意料,但也情理之中,对一个已经释放的对象重新赋值,必然导致程序奔溃,这样的程序是非常不安全。




AutoPtr<int> ap1(FunTest());
system("pause");
return 0;
}
AutoPtr<int> FunTest()
{
AutoPtr<int> p(new int(1));
return p;
}

int main()
{
AutoPtr<int> p(AutoPtr<int>(new int(1)));
system("pause");
return 0;
}

在VS2017下,这段程序是正常执行的,在new一个对象时产生了一个无名对象,无名对象是具有常性的,在拷贝构造无名对象时,拷贝构造函数应该用const类型的参数来接收,但是这样的程序却成功运行了,原因就在于VS2017下编译器对其进行了优化,即不会再去调用它的拷贝构造函数,而是直接取调用构造函数。
为了验证这个程序的跨平台效果,我决定在g++上测试一下程序的正确性:
在这里插入图片描述

我们发现在g++上测试编译阶段都过不了,用一个具有常性的对象去拷贝构造一个对象时,必须用const类型对象的引用来接收具有const性质的的对象。

猜你喜欢

转载自blog.csdn.net/xiaodu655/article/details/85780663