智能指针auto_ptr的解析

智能指针(smart pointer)是一个c++中必须去探讨的一个重点知识,它代理了原有的“裸指针”的一些行为,并添加了很多特性。


auto_ptr是为了解决资源泄漏的问题提供的一个智能指针类模板(注意:这只是一种简单的智能指针且很不完善,不推荐使用)
先用例子说明下

int main ()
{
    auto ptr< class_need_resource > p1(new class_ need_resource);
    auto_ptr<demo_class> p2(factory.create());
    ...
}
/*离开作用域,pl、P2 自动析构从而释放内存等资源
auto_ptr的构造函数接受new操作符或者对象工厂创建出的对象指针作为参数,
从而代理了原始指针。虽然它是一个对象,但因为重载了operator*和opreator->,
其行为非常类似指针,可以把它用在大多数普通指针可用的地方。当退出作用域时(离开函数main() 或者发生
异常),C++语言会保证auto_ptr对象销毁,调用auto_ptr的析构函数,进而使用delete
操作符删除原始指针释放资源*/

auto_ptr的实现原理:它是对原有裸指针进行包装后形成的一个类,并在类的析构函数中实现对指针所指空间的释放(delete),从而避免了因为程序员的大意而缺少的空间释放,而解决c/c++中饱受诟病的内存泄漏问题,因为类的析构是自动调用的。
比如,如果该类有2个成员变量,指向两个资源,在构造函数中申请资源A成功,但申请资源B失败,则构造函数失败,那么析构函数不会被调用,那么资源A则泄漏。
我们可以利用auto_ptr取代普通指针作为成员变量,这样首先调用成功的成员变量的构造函数肯定会调用其析构函数,那么就可以避免资源泄漏问题。


源代码的解析

//下面便是auto_ptr智能指针类模板的定义
template<class _Ty>
class auto_ptr {
public:
    typedef _Ty element_type; //简单的类型的替换,更方便阅读
    explicit auto_ptr(_Ty *_P = 0) _THROWO() //explicit关键字避免隐式转换,构造函数传入原始指针进行包装构造成智能指针对象
        :_Owns(_P != 0),_Ptr(_P) {}
    auto_ptr (const auto_ptr<_Ty>& _Y) _THROWO() //拷贝构造函数
        :_Owns(_Y._Owns),_Ptr(_Y.release()) {}
    auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROWO() //重载=运算符,此函数很严谨,值得学习
            {if (this != &_Y)           //先判断是不是自己给自己赋值
                {if (_Ptr != ._Y.get()) //判断两个智能指针对象是不是指向同一块内存
                    {if (_Owns)         //判断=左值对象是否拥有空间所有权,拥有先释放本智能指针空间,再赋值
                        delete _Ptr;}
                     else if (_Y._Owns) //判断=的右值对象是否拥有所有权,有则将所有权授给=左值对象,即_Owns = true
                         _Owns = true;
                    _Ptr = _Y.Owns;}
    return (*this);}
    ~auto_ptr()     //析构函数,先判断是否拥有空间所有权,再释放或者直接返回
        {if(_Owns)
                delete_Ptr; }
    _Ty& operator*()const _THROWO() //重载*运算符
        {return (*get()); }
    _Ty *operator->()const _THROWO()//重载->运算符,这都是让这个对象拥有原始指针同样的操作,而等价为指针;
        {return (get());}
    _Ty *get() const _THROWO
        {return (_Ptr); }
    _Ty *release() const _THROWO()  //释放拥有权,_Owns = false
        {((auto_ptr<_Ty> *)this)->_Owns = false;
        return (Ptr); }
private :
    bool _Owns;  //1代表拥有空间所有权,0则相反
    _Ty *_Ptr;   //所封装的原始指针
J;

auto_ptr十分不完善,也存在很多漏洞,一般不使用:
例如:

/*智能指针管理多个对象的问题*/  
void test2(){  
    auto_ptr<A> pa(new A[3]);//核心转存,解映射出错  
    /*为什么智能指针不能管理对象数组*/  
}  

一次分配多个对象我们必须要用delete[]去释放,不然会出错。最终的问题其实就是delete和delete[]的区别问题。delete用于释放单个对象,获取的是对象的地址,并且调用free,而对象数组的分配有所不同,除了分配所需要大小的堆内存空间外,这段堆内存的开头还分配了4个字节的空间,用于存放分配对象的个数,在释放的时候必须把最开头的四个字节包含进去,delete[]在释放的时候,将得到的地址减4,这样取得了最开始的地址,这样的释放才是正确的释放,而delete的释放并没有减4的操作,所以无法正确的释放 。`

又比方说:auto_ptr虽和其它智能指针同样,只保留一个对象所有权,但这样简单粗暴不合逻辑的所有权转接是不实际的。

值得说明的是在c++2011中出现的smart_ptr指针,真正做到了“智能”,其不仅可以管理对象数组,还具有指针的拷贝语义,在管理对象数组上smart_ptr采用了特化的处理,而在处理拷贝语义上采用了设置计数器这里不做详细说明。当然还有许多更好的scoped_ptr,scoped_array,shared_ptr,shared_array,weak_ptr等后续我们会继续剖析他们。

猜你喜欢

转载自blog.csdn.net/return_cc/article/details/79372495
今日推荐