zoukankan      html  css  js  c++  java
  • 【C++深入浅出】智能指针之auto_ptr学习

    起: 

    C++98标准加入auto_ptr,即智能指针,C++11加入shared_ptr和weak_ptr两种智能指针,先从auto_ptr的定义学习一下auto_ptr的用法。

    template<class _Ty>
    class auto_ptr
    { // wrap an object pointer to ensure destruction
    public:
    //定义_Myt类型,作用域局限于类中,便于书写和理解
    typedef auto_ptr<_Ty> _Myt;
    typedef _Ty element_type;
    //显式调用构造函数,对类型进行检查并构造一个_Ty类型的指针
    //未定义默认构造函数 
    explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
    : _Myptr(_Ptr)
    { // construct from object pointer
    }
    //定义了复制构造函数,稍微有些奇特的复制构造函数,构造了this以后,_Right就会变成一个_Myt类型的NULL指针,这点须谨记,具体参见release的定义。
    //上面即所有权转移,同一个指针在多个auto_ptr对象之间只会存在一份所有权,可以避免析构的重复delete错误。
    auto_ptr(_Myt& _Right) _THROW0()
    : _Myptr(_Right.release())
    { // construct by assuming pointer from _Right auto_ptr
    }
    //通过auto_ptr_ref结构体来构造智能指针,所有权转移
    auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()
    { // construct by assuming pointer from _Right auto_ptr_ref
    _Ty *_Ptr = _Right._Ref;
    _Right._Ref = 0; // release old
    _Myptr = _Ptr; // reset this
    }
    //不是很理解,希望大神指点一下,我的理解是将类型可以隐式转换的指针
    template<class _Other>
    operator auto_ptr<_Other>() _THROW0()
    { // convert to compatible auto_ptr
    return (auto_ptr<_Other>(*this));
    }
    template<class _Other>
    operator auto_ptr_ref<_Other>() _THROW0()
    { // convert to compatible auto_ptr_ref
    _Other *_Cvtptr = _Myptr; // test implicit conversion
    auto_ptr_ref<_Other> _Ans(_Cvtptr);
    _Myptr = 0; // pass ownership to auto_ptr_ref
    return (_Ans);
    }
    //赋值操作符=的重载函数之一:独占新指针的所有权并delete当前拥有的指针
    template<class _Other>
    _Myt& operator=(auto_ptr<_Other>& _Right) _THROW0()
    { // assign compatible _Right (assume pointer)
    reset(_Right.release());
    return (*this);
    }
    template<class _Other>
    auto_ptr(auto_ptr<_Other>& _Right) _THROW0()
    : _Myptr(_Right.release())
    { // construct by assuming pointer from _Right
    }
    //赋值操作符=的重载之一:独占新指针的所有权并delete当前拥有的指针
    _Myt& operator=(_Myt& _Right) _THROW0()
    { // assign compatible _Right (assume pointer)
    reset(_Right.release());
    return (*this);
    }
    //赋值操作符=的重载之一:独占新指针的所有权并delete当前拥有的指针
    _Myt& operator=(auto_ptr_ref<_Ty> _Right) _THROW0()
    { // assign compatible _Right._Ref (assume pointer)
    _Ty *_Ptr = _Right._Ref;
    _Right._Ref = 0; // release old
    reset(_Ptr); // set new
    return (*this);
    }
    //析构删除当前指向的资源,用的delete而非delete [],所以只能用来删除单个抽象数据对象,不能删除数组,需要关注,指向的对象应该是用new构造出来的,而不是new []构造的。
    ~auto_ptr() _NOEXCEPT
    { // destroy the object
    delete _Myptr;
    }
    //重载*操作符,返回指向的对象
    _Ty& operator*() const _THROW0()
    { // return designated value
     #if _ITERATOR_DEBUG_LEVEL == 2
    if (_Myptr == 0)
    _DEBUG_ERROR("auto_ptr not dereferencable");
     #endif /* _ITERATOR_DEBUG_LEVEL == 2 */
    return (*get());
    }
    //重载操作符->,内部调用get()方法
    _Ty *operator->() const _THROW0()
    { // return pointer to class object
     #if _ITERATOR_DEBUG_LEVEL == 2
    if (_Myptr == 0)
    _DEBUG_ERROR("auto_ptr not dereferencable");
     #endif /* _ITERATOR_DEBUG_LEVEL == 2 */
    return (get());
    }
    //返回指向资源的指针
    _Ty *get() const _THROW0()
    { // return wrapped pointer
    return (_Myptr);
    }
    //将this指针指向NULL,并返回指向资源的指针
    _Ty *release() _THROW0()
    { // return wrapped pointer and give up ownership
    _Ty *_Tmp = _Myptr;
    _Myptr = 0;
    return (_Tmp);
    }
    //delete已拥有的指针并获取新的指针所有权,reset使用时候要注意这一点
    void reset(_Ty *_Ptr = 0)
    { // destroy designated object and store new pointer
    if (_Ptr != _Myptr)
    delete _Myptr;
    _Myptr = _Ptr;
    }
    private:
    _Ty *_Myptr; // the wrapped object pointer
    };
    学习小结:
    1. 每一个auto_ptr都是一个ADT对象,auto_ptr应当被定义成局部或临时变量,以便自动析构拥有的指针。
    2. auto_ptr中很重要的一个理念就是所有权转移,所有权转移就是auto_ptr会接管赋给他们的指针的所有权,以后这个指针有且仅有一个auto_ptr拥有。复制构造和赋值操作都会接管指针的所有权。
    3. 从整个设计理念看,get()和release()提供了某些灵活性的同时破坏了概念的一致性,使用不当会导致某些错误,所有权不再由唯一的auto_ptr具有,要少用这两个接口。
    4. auto_ptr适用于管理new出来的指针,不适用new[]出来的指针,也不要用auto_ptr指向静态分配对象的指针。
    5. auto_ptr不满足STL容器的基本要求,因为auto_ptr的复制操作是所有权的转移,而不是所有权的拷贝,不要试图用容器来容纳auto_ptr,也不适用sort等内部会对元素进行拷贝的函数。
    6. auto_ptr提供的接口列表:显式构造函数、复制构造函数的各个重载版本、赋值操作符的各个重载版本、操作符*、操作符->、release()、get()、reset()。

     后记:

    学习boost,认为boost中的一种与auto_ptr极其类似的智能指针scoped_ptr的设计是不错的,auto_ptr的所有权可以转移,同一时间只有一个auto_ptr可以管理指针,但还是具有一定的危险性,而scoped_ptr把拷贝构造函数和赋值函数全都私有化,保证了指针的绝对安全,从概念上保持了完整性,大多数时候是一种更好的选择。

  • 相关阅读:
    Ubuntu 16.04 LTS安装好之后需要做的15件事
    双目立体视觉
    Win7、Ubuntu双系统正确卸载Ubuntu系统
    推荐一个计算机视觉图书:python计算机视觉编程
    深度学习从被监督走向互动
    详细解读神经网络十大误解,再也不会弄错它的工作原理
    不为人知的springboot的技巧
    并发情况下引发的血案
    slor6.6 在linux下的安装以及启动失败解决办法
    springmvc源码阅读2--dispatcherServlet及谈如何找源码入口
  • 原文地址:https://www.cnblogs.com/learn-my-life/p/3753205.html
Copyright © 2011-2022 走看看