智能指针

C++里面的智能指针包括auto_ptr, shared_ptr, unique_ptr, weak_ptr四种。
auto_ptr

template
    class auto_ptr
        {   // wrap an object pointer to ensure destruction
public:
    typedef auto_ptr<_Ty> _Myt;
    typedef _Ty element_type;

    explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
        : _Myptr(_Ptr)
        {   // construct from object pointer
        }

    auto_ptr(_Myt& _Right) _THROW0()
        : _Myptr(_Right.release())
        {   // construct by assuming pointer from _Right auto_ptr
        }

    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
        operator auto_ptr<_Other>() _THROW0()
        {   // convert to compatible auto_ptr
        return (auto_ptr<_Other>(*this));
        }

    template
        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);
        }

    template
        _Myt& operator=(auto_ptr<_Other>& _Right) _THROW0()
        {   // assign compatible _Right (assume pointer)
        reset(_Right.release());
        return (*this);
        }

    template
        auto_ptr(auto_ptr<_Other>& _Right) _THROW0()
        : _Myptr(_Right.release())
        {   // construct by assuming pointer from _Right
        }

    _Myt& operator=(_Myt& _Right) _THROW0()
        {   // assign compatible _Right (assume pointer)
        reset(_Right.release());
        return (*this);
        }

    _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);
        }

    ~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());
        }

    _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);
        }

    _Ty *release() _THROW0()
        {   // return wrapped pointer and give up ownership
        _Ty *_Tmp = _Myptr;
        _Myptr = 0;
        return (_Tmp);
        }

    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
    };

auto_ptr的拷贝构造函数, 拷贝赋值函数用得都是非const的引用类型, 我们可以修改源对象。例如:

 std::auto_ptr my_memory(new Simple(1));
    std::auto_ptr my_memory2;   // 创建一个新的 my_memory2 对象
    my_memory2 = my_memory;             // 复制旧的 my_memory 给 my_memory2
    my_memory2->PrintSomething();       // 输出信息,复制成功
    my_memory->PrintSomething();        // 崩溃

当使用=号赋值操作时, my_memory2完全剥夺了my_memory的内存管理所有权, 导致my_memory悬空, 最后使用时崩溃。
std::auto_ptr 的 release() 函数只是让出内存所有权,这显然也不符合 C++ 编程思想。
总结:std::auto_ptr 可用来管理单个对象的对内存,但是,请注意如下几点:
(1) 尽量不要使用“operator=”。如果使用了,请不要再使用先前对象。
(2) 记住 release() 函数不会释放对象,仅仅归还所有权。
(3) std::auto_ptr 最好不要当成参数传递(读者可以自行写代码确定为什么不能)。
(4) 由于 std::auto_ptr 的“operator=”问题,有其管理的对象不能放入 std::vector 等容器中。


unique_ptr

template  // = default_delete<_Ty>
    class unique_ptr
        : private _Unique_ptr_base<_Ty, _Dx,
            is_empty<_Dx>::value
                || is_same, _Dx>::value>
    {   // non-copyable pointer to an object
public:
    typedef unique_ptr<_Ty, _Dx> _Myt;
    typedef _Unique_ptr_base<_Ty, _Dx,
        is_empty<_Dx>::value
            || is_same, _Dx>::value> _Mybase;
    typedef typename _Mybase::pointer pointer;
    typedef _Ty element_type;
    typedef _Dx deleter_type;

    using _Mybase::get_deleter;

    unique_ptr() _NOEXCEPT
        : _Mybase(pointer())
        {   // default construct
        static_assert(!is_pointer<_Dx>::value,
            "unique_ptr constructed with null deleter pointer");
        }

    unique_ptr(nullptr_t) _NOEXCEPT
        : _Mybase(pointer())
        {   // null pointer construct
        static_assert(!is_pointer<_Dx>::value,
            "unique_ptr constructed with null deleter pointer");
        }

    _Myt& operator=(nullptr_t) _NOEXCEPT
        {   // assign a null pointer
        reset();
        return (*this);
        }

    explicit unique_ptr(pointer _Ptr) _NOEXCEPT
        : _Mybase(_Ptr)
        {   // construct with pointer
        static_assert(!is_pointer<_Dx>::value,
            "unique_ptr constructed with null deleter pointer");
        }

    unique_ptr(pointer _Ptr,
        typename _If::value, _Dx,
            const typename remove_reference<_Dx>::type&>::type _Dt) _NOEXCEPT
        : _Mybase(_Ptr, _Dt)
        {   // construct with pointer and (maybe const) deleter&
        }

    unique_ptr(pointer _Ptr,
        typename remove_reference<_Dx>::type&& _Dt) _NOEXCEPT
        : _Mybase(_Ptr, _STD move(_Dt))
        {   // construct by moving deleter
        static_assert(!is_reference<_Dx>::value,
            "unique_ptr constructed with reference to rvalue deleter");
        }

    unique_ptr(unique_ptr&& _Right) _NOEXCEPT
        : _Mybase(_Right.release(),
            _STD forward<_Dx>(_Right.get_deleter()))
        {   // construct by moving _Right
        }

    template::value
            && is_convertible::pointer,
                pointer>::value
            && ((is_reference<_Dx>::value && is_same<_Dx, _Dx2>::value)
                || (!is_reference<_Dx>::value
                    && is_convertible<_Dx2, _Dx>::value)),
            void>::type>
        unique_ptr(unique_ptr<_Ty2, _Dx2>&& _Right) _NOEXCEPT
            : _Mybase(_Right.release(),
                _STD forward<_Dx2>(_Right.get_deleter()))
        {   // construct by moving _Right
        }

    template::value
            && is_same<_Dx, default_delete<_Ty> >::value,
            void>::type>
        unique_ptr(auto_ptr<_Ty2>&& _Right) _NOEXCEPT
            : _Mybase(_Right.release())
        {   // construct by moving _Right
        }

    template
        typename enable_if::value
            && is_convertible::pointer,
                pointer>::value,
            _Myt&>::type
        operator=(unique_ptr<_Ty2, _Dx2>&& _Right) _NOEXCEPT
        {   // assign by moving _Right
        reset(_Right.release());
        this->get_deleter() = _STD forward<_Dx2>(_Right.get_deleter());
        return (*this);
        }

    _Myt& operator=(_Myt&& _Right) _NOEXCEPT
        {   // assign by moving _Right
        if (this != &_Right)
            {   // different, do the move
            reset(_Right.release());
            this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
            }
        return (*this);
        }

    void swap(_Myt& _Right) _NOEXCEPT
        {   // swap elements
        _Swap_adl(this->_Myptr, _Right._Myptr);
        _Swap_adl(this->get_deleter(),
            _Right.get_deleter());
        }

    ~unique_ptr() _NOEXCEPT
        {   // destroy the object
        if (this->_Myptr != pointer())
            this->get_deleter()(this->_Myptr);
        }

    typename add_reference<_Ty>::type operator*() const
        {   // return reference to object
        return (*this->_Myptr);
        }

    pointer operator->() const _NOEXCEPT
        {   // return pointer to class object
        return (_STD pointer_traits::pointer_to(**this));
        }

    pointer get() const _NOEXCEPT
        {   // return pointer to object
        return (this->_Myptr);
        }

    explicit operator bool() const _NOEXCEPT
        {   // test for non-null pointer
        return (this->_Myptr != pointer());
        }

    pointer release() _NOEXCEPT
        {   // yield ownership of pointer
        pointer _Ans = this->_Myptr;
        this->_Myptr = pointer();
        return (_Ans);
        }

    void reset(pointer _Ptr = pointer()) _NOEXCEPT
        {   // establish new pointer
        pointer _Old = this->_Myptr;
        this->_Myptr = _Ptr;
        if (_Old != pointer())
            this->get_deleter()(_Old);
        }

    unique_ptr(const _Myt&) = delete;
    _Myt& operator=(const _Myt&) = delete;
    };

unique_ptr禁止了拷贝和赋值操作, 一个unique_ptr拥有它指向的对象。
release函数返回unique_ptr当前保存的指针并将其置为空,reset函数接受一个可选的指针参数, 令unique_ptr重新指向给定的指针。
shared_ptr

template
    class shared_ptr
        : public _Ptr_base<_Ty>
    {   // class for reference counted resource management
public:
    typedef shared_ptr<_Ty> _Myt;
    typedef _Ptr_base<_Ty> _Mybase;

    shared_ptr() _NOEXCEPT
        {   // construct empty shared_ptr
        }

    template
        explicit shared_ptr(_Ux *_Px)
        {   // construct shared_ptr object that owns _Px
        _Resetp(_Px);
        }

    template
        shared_ptr(_Ux *_Px, _Dx _Dt)
        {   // construct with _Px, deleter
        _Resetp(_Px, _Dt);
        }

    shared_ptr(nullptr_t)
        {   // construct empty shared_ptr
        }

    template
        shared_ptr(nullptr_t, _Dx _Dt)
        {   // construct with nullptr, deleter
        _Resetp((_Ty *)0, _Dt);
        }

    template
        shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
        {   // construct with nullptr, deleter, allocator
        _Resetp((_Ty *)0, _Dt, _Ax);
        }

    template
        shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
        {   // construct with _Px, deleter, allocator
        _Resetp(_Px, _Dt, _Ax);
        }

    template
        shared_ptr(const shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT
        {   // construct shared_ptr object that aliases _Right
        this->_Reset(_Px, _Right);
        }

    shared_ptr(const _Myt& _Other) _NOEXCEPT
        {   // construct shared_ptr object that owns same resource as _Other
        this->_Reset(_Other);
        }

    template::value,
            void>::type>
        shared_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
        {   // construct shared_ptr object that owns same resource as _Other
        this->_Reset(_Other);
        }

    template
        explicit shared_ptr(const weak_ptr<_Ty2>& _Other,
            bool _Throw = true)
        {   // construct shared_ptr object that owns resource *_Other
        this->_Reset(_Other, _Throw);
        }

    template
        shared_ptr(auto_ptr<_Ty2>&& _Other)
        {   // construct shared_ptr object that owns *_Other.get()
        this->_Reset(_STD move(_Other));
        }

    template
        shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag)
        {   // construct shared_ptr object for static_pointer_cast
        this->_Reset(_Other, _Tag);
        }

    template
        shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag)
        {   // construct shared_ptr object for const_pointer_cast
        this->_Reset(_Other, _Tag);
        }

    template
        shared_ptr(const shared_ptr<_Ty2>& _Other, const _Dynamic_tag& _Tag)
        {   // construct shared_ptr object for dynamic_pointer_cast
        this->_Reset(_Other, _Tag);
        }

    shared_ptr(_Myt&& _Right) _NOEXCEPT
        : _Mybase(_STD forward<_Myt>(_Right))
        {   // construct shared_ptr object that takes resource from _Right
        }

    template::value,
            void>::type>
        shared_ptr(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
        : _Mybase(_STD forward >(_Right))
        {   // construct shared_ptr object that takes resource from _Right
        }

    template
        shared_ptr(unique_ptr<_Ux, _Dx>&& _Right)
        {   // construct from unique_ptr
        _Resetp(_Right.release(), _Right.get_deleter());
        }

    template
        _Myt& operator=(unique_ptr<_Ux, _Dx>&& _Right)
        {   // move from unique_ptr
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    _Myt& operator=(_Myt&& _Right) _NOEXCEPT
        {   // construct shared_ptr object that takes resource from _Right
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    template
        _Myt& operator=(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
        {   // construct shared_ptr object that takes resource from _Right
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    ~shared_ptr() _NOEXCEPT
        {   // release resource
        this->_Decref();
        }

    _Myt& operator=(const _Myt& _Right) _NOEXCEPT
        {   // assign shared ownership of resource owned by _Right
        shared_ptr(_Right).swap(*this);
        return (*this);
        }

    template
        _Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
        {   // assign shared ownership of resource owned by _Right
        shared_ptr(_Right).swap(*this);
        return (*this);
        }

    template
        _Myt& operator=(auto_ptr<_Ty2>&& _Right)
        {   // assign ownership of resource pointed to by _Right
        shared_ptr(_STD move(_Right)).swap(*this);
        return (*this);
        }

    void reset() _NOEXCEPT
        {   // release resource and convert to empty shared_ptr object
        shared_ptr().swap(*this);
        }

    template
        void reset(_Ux *_Px)
        {   // release, take ownership of _Px
        shared_ptr(_Px).swap(*this);
        }

    template
        void reset(_Ux *_Px, _Dx _Dt)
        {   // release, take ownership of _Px, with deleter _Dt
        shared_ptr(_Px, _Dt).swap(*this);
        }

    template
        void reset(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
        {   // release, take ownership of _Px, with deleter _Dt, allocator _Ax
        shared_ptr(_Px, _Dt, _Ax).swap(*this);
        }

    void swap(_Myt& _Other) _NOEXCEPT
        {   // swap pointers
        this->_Swap(_Other);
        }

    _Ty *get() const _NOEXCEPT
        {   // return pointer to resource
        return (this->_Get());
        }

    typename add_reference<_Ty>::type operator*() const _NOEXCEPT
        {   // return reference to resource
        return (*this->_Get());
        }

    _Ty *operator->() const _NOEXCEPT
        {   // return pointer to resource
        return (this->_Get());
        }

    bool unique() const _NOEXCEPT
        {   // return true if no other shared_ptr object owns this resource
        return (this->use_count() == 1);
        }

    explicit operator bool() const _NOEXCEPT
        {   // test if shared_ptr object owns no resource
        return (this->_Get() != 0);
        }

private:
    template
        void _Resetp(_Ux *_Px)
        {   // release, take ownership of _Px
        _TRY_BEGIN  // allocate control block and reset
        _Resetp0(_Px, new _Ref_count<_Ux>(_Px));
        _CATCH_ALL  // allocation failed, delete resource
        delete _Px;
        _RERAISE;
        _CATCH_END
        }

    template
        void _Resetp(_Ux *_Px, _Dx _Dt)
        {   // release, take ownership of _Px, deleter _Dt
        _TRY_BEGIN  // allocate control block and reset
        _Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt));
        _CATCH_ALL  // allocation failed, delete resource
        _Dt(_Px);
        _RERAISE;
        _CATCH_END
        }

    template
        void _Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
        {   // release, take ownership of _Px, deleter _Dt, allocator _Ax
        typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd;
        typename _Alloc::template rebind<_Refd>::other _Al = _Ax;

        _TRY_BEGIN  // allocate control block and reset
        _Refd *_Ptr = _Al.allocate(1);
        ::new (_Ptr) _Refd(_Px, _Dt, _Al);
        _Resetp0(_Px, _Ptr);
        _CATCH_ALL  // allocation failed, delete resource
        _Dt(_Px);
        _RERAISE;
        _CATCH_END
        }

public:
    template
        void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
        {   // release resource and take ownership of _Px
        this->_Reset0(_Px, _Rx);
        _Enable_shared(_Px, _Rx);
        }
    };

weak_ptr

    // TEMPLATE CLASS weak_ptr
template
    class weak_ptr
        : public _Ptr_base<_Ty>
    {   // class for pointer to reference counted resource
public:
    weak_ptr() _NOEXCEPT
        {   // construct empty weak_ptr object
        }

    weak_ptr(const weak_ptr& _Other) _NOEXCEPT
        {   // construct weak_ptr object for resource pointed to by _Other
        this->_Resetw(_Other);
        }

    template::value,
            void>::type>
        weak_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
        {   // construct weak_ptr object for resource owned by _Other
        this->_Resetw(_Other);
        }

    template::value,
            void>::type>
        weak_ptr(const weak_ptr<_Ty2>& _Other) _NOEXCEPT
        {   // construct weak_ptr object for resource pointed to by _Other
        this->_Resetw(_Other.lock());
        }

    ~weak_ptr() _NOEXCEPT
        {   // release resource
        this->_Decwref();
        }

    weak_ptr& operator=(const weak_ptr& _Right) _NOEXCEPT
        {   // assign from _Right
        this->_Resetw(_Right);
        return (*this);
        }

    template
        weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) _NOEXCEPT
        {   // assign from _Right
        this->_Resetw(_Right.lock());
        return (*this);
        }
    template
        weak_ptr& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
        {   // assign from _Right
        this->_Resetw(_Right);
        return (*this);
        }

    void reset() _NOEXCEPT
        {   // release resource, convert to null weak_ptr object
        this->_Resetw();
        }

    void swap(weak_ptr& _Other) _NOEXCEPT
        {   // swap pointers
        this->_Swap(_Other);
        }

    bool expired() const _NOEXCEPT
        {   // return true if resource no longer exists
        return (this->_Expired());
        }

    shared_ptr<_Ty> lock() const _NOEXCEPT
        {   // convert to shared_ptr
        return (shared_ptr<_Ty>(*this, false));
        }
    };

weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。同样,在weak_ptr析构时也不会导致引用计数的减少,它只是一个静静地观察者。weak_ptr没有重载operator*和->,这是特意的,因为它不共享指针,不能操作资源,这是它弱的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,从而操作资源。

weak_ptr用于解决”引用计数”模型循环依赖问题,weak_ptr指向一个对象,并不增减该对象的引用计数器。weak_ptr用于配合shared_ptr使用,并不影响动态对象的生命周期,即其存在与否并不影响对象的引用计数器。weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象。weak_ptr提供了expired()与lock()成员函数,前者用于判断weak_ptr指向的对象是否已被销毁,后者返回其所指对象的shared_ptr智能指针(对象销毁时返回”空”shared_ptr)。

你可能感兴趣的:(智能指针)