美文网首页
智能指针

智能指针

作者: 扎Zn了老Fe | 来源:发表于2017-09-05 23:14 被阅读0次

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

    template<class _Ty>
        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<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);
            }
    
        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
            }
    
        _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<Simple> my_memory(new Simple(1));
        std::auto_ptr<Simple> 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<class _Ty,
        class _Dx>  // = default_delete<_Ty>
        class unique_ptr
            : private _Unique_ptr_base<_Ty, _Dx,
                is_empty<_Dx>::value
                    || is_same<default_delete<_Ty>, _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<default_delete<_Ty>, _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<is_reference<_Dx>::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<class _Ty2,
            class _Dx2,
            class = typename enable_if<!is_array<_Ty2>::value
                && is_convertible<typename unique_ptr<_Ty2, _Dx2>::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<class _Ty2,
            class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::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<class _Ty2,
            class _Dx2>
            typename enable_if<!is_array<_Ty2>::value
                && is_convertible<typename unique_ptr<_Ty2, _Dx2>::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>::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 _Ty>
        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<class _Ux>
            explicit shared_ptr(_Ux *_Px)
            {   // construct shared_ptr object that owns _Px
            _Resetp(_Px);
            }
    
        template<class _Ux,
            class _Dx>
            shared_ptr(_Ux *_Px, _Dx _Dt)
            {   // construct with _Px, deleter
            _Resetp(_Px, _Dt);
            }
    
        shared_ptr(nullptr_t)
            {   // construct empty shared_ptr
            }
    
        template<class _Dx>
            shared_ptr(nullptr_t, _Dx _Dt)
            {   // construct with nullptr, deleter
            _Resetp((_Ty *)0, _Dt);
            }
    
        template<class _Dx,
            class _Alloc>
            shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
            {   // construct with nullptr, deleter, allocator
            _Resetp((_Ty *)0, _Dt, _Ax);
            }
    
        template<class _Ux,
            class _Dx,
            class _Alloc>
            shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
            {   // construct with _Px, deleter, allocator
            _Resetp(_Px, _Dt, _Ax);
            }
    
        template<class _Ty2>
            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<class _Ty2,
            class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::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<class _Ty2>
            explicit shared_ptr(const weak_ptr<_Ty2>& _Other,
                bool _Throw = true)
            {   // construct shared_ptr object that owns resource *_Other
            this->_Reset(_Other, _Throw);
            }
    
        template<class _Ty2>
            shared_ptr(auto_ptr<_Ty2>&& _Other)
            {   // construct shared_ptr object that owns *_Other.get()
            this->_Reset(_STD move(_Other));
            }
    
        template<class _Ty2>
            shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag)
            {   // construct shared_ptr object for static_pointer_cast
            this->_Reset(_Other, _Tag);
            }
    
        template<class _Ty2>
            shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag)
            {   // construct shared_ptr object for const_pointer_cast
            this->_Reset(_Other, _Tag);
            }
    
        template<class _Ty2>
            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<class _Ty2,
            class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
                void>::type>
            shared_ptr(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
            : _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right))
            {   // construct shared_ptr object that takes resource from _Right
            }
    
        template<class _Ux,
            class _Dx>
            shared_ptr(unique_ptr<_Ux, _Dx>&& _Right)
            {   // construct from unique_ptr
            _Resetp(_Right.release(), _Right.get_deleter());
            }
    
        template<class _Ux,
            class _Dx>
            _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<class _Ty2>
            _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<class _Ty2>
            _Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
            {   // assign shared ownership of resource owned by _Right
            shared_ptr(_Right).swap(*this);
            return (*this);
            }
    
        template<class _Ty2>
            _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<class _Ux>
            void reset(_Ux *_Px)
            {   // release, take ownership of _Px
            shared_ptr(_Px).swap(*this);
            }
    
        template<class _Ux,
            class _Dx>
            void reset(_Ux *_Px, _Dx _Dt)
            {   // release, take ownership of _Px, with deleter _Dt
            shared_ptr(_Px, _Dt).swap(*this);
            }
    
        template<class _Ux,
            class _Dx,
            class _Alloc>
            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<class _Ux>
            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<class _Ux,
            class _Dx>
            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<class _Ux,
            class _Dx,
            class _Alloc>
            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<class _Ux>
            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 _Ty>
        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<class _Ty2,
            class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
                void>::type>
            weak_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
            {   // construct weak_ptr object for resource owned by _Other
            this->_Resetw(_Other);
            }
    
        template<class _Ty2,
            class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::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<class _Ty2>
            weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) _NOEXCEPT
            {   // assign from _Right
            this->_Resetw(_Right.lock());
            return (*this);
            }
        template<class _Ty2>
            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)。

    相关文章

      网友评论

          本文标题:智能指针

          本文链接:https://www.haomeiwen.com/subject/aiofjxtx.html