STL(五)之智能指针剖析

_Mutex_base

template<_Lock_policy _Lp>
class _Mutex_base
{
    protected:
        enum { _S_need_barriers = 0 };
};

template<>
class _Mutex_base<_S_mutex : public __gnu_cxx::__mutex
{
    protected:
        enum { _S_need_barriers = 1 };
};

_Sp_counted_base

template<_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base : public _Mutex_base<_Lp>
{
    public:
        _Sp_counted_base() : _M_use_count(1), _M_weak_count(1) { }
        virtual ~_Sp_counted_base() { }        //nothrow
        virtual void _M_dispose() = 0; // nothrow
        virtual void _M_destroy() { delete this; }
        virtual void* _M_get_deleter(const std::type_info&) = 0;
        void _M_add_ref_copy() { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
        void _M_add_ref_lock();
        void _M_release() // nothrow
        {
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
            if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
            {
                _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
                _M_dispose();
                if (_Mutex_base<_Lp>::_S_need_barriers)
                    __atomic_thread_fence (__ATOMIC_ACQ_REL);

                _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
                if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
                {
                    _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
                    _M_destroy();
                }
            }
        }   

        void _M_weak_add_ref() // nothrow
        { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }

        void _M_weak_release() // nothrow
        {
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
            if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
            {
                _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
                    if (_Mutex_base<_Lp>::_S_need_barriers)
                        __atomic_thread_fence (__ATOMIC_ACQ_REL);
                _M_destroy();
            }
        }   

        long _M_get_use_count() const // nothrow
        { return const_cast<const volatile _Atomic_word&>(_M_use_count); }

    private:
        _Sp_counted_base(_Sp_counted_base const&);
        _Sp_counted_base& operator=(_Sp_counted_base const&);

        _Atomic_word  _M_use_count;     // #shared
        _Atomic_word  _M_weak_count;    // #weak + (#shared != 0)
};

template<>
inline void _Sp_counted_base<_S_single>::_M_add_ref_lock()
{
    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
    {
        _M_use_count = 0;
        __throw_bad_weak_ptr();
    }
}

template<>
inline void _Sp_counted_base<_S_mutex>::_M_add_ref_lock()
{
    __gnu_cxx::__scoped_lock sentry(*this);
    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
    {
        _M_use_count = 0;
        __throw_bad_weak_ptr();
    }
}

template<>
inline void _Sp_counted_base<_S_atomic>::_M_add_ref_lock()
{
    _Atomic_word __count = _M_use_count;
    do
    {
        if (__count == 0)
        __throw_bad_weak_ptr();
    }
    while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED));
}

_Sp_counted_base_Impl

template<typename _Ptr, typename _Deleter, _Lock_policy _Lp>
class _Sp_counted_base_impl : public _Sp_counted_base<_Lp>
{
    public:
        _Sp_counted_base_impl(_Ptr __p, _Deleter __d) : _M_ptr(__p), _M_del(__d) { }
        virtual void _M_dispose(){ _M_del(_M_ptr); }
        virtual void* _M_get_deleter(const std::type_info& __ti){ return _M_del ; }

    private:
        _Sp_counted_base_impl(const _Sp_counted_base_impl&);
        _Sp_counted_base_impl& operator=(const _Sp_counted_base_impl&);

        _Ptr      _M_ptr;  // copy constructor must not throw
        _Deleter  _M_del;  // copy constructor must not throw
    };

_Sp_deleter

template<typename _Tp>
struct _Sp_deleter
{
    typedef void result_type;
    typedef _Tp* argument_type;
    void operator()(_Tp* __p) const { delete __p; }
};

__shared_count

template<_Lock_policy _Lp = __default_lock_policy>
class __shared_count
{
    public:
        __shared_count() : _M_pi(0) { }

        template<typename _Ptr>
        __shared_count(_Ptr __p) : _M_pi(0)
        {
            __try
            {
                typedef typename std::tr1::remove_pointer<_Ptr>::type _Tp;
                _M_pi = new _Sp_counted_base_impl<_Ptr, _Sp_deleter<_Tp>, _Lp>(
                __p, _Sp_deleter<_Tp>());
            }
            __catch(...)
            {
                delete __p;
                __throw_exception_again;
            }
        }

        template<typename _Ptr, typename _Deleter>
        __shared_count(_Ptr __p, _Deleter __d) : _M_pi(0)
        {
            __try
            {
                _M_pi = new _Sp_counted_base_impl<_Ptr, _Deleter, _Lp>(__p, __d);
            }
            __catch(...)
            {
                __d(__p); // Call _Deleter on __p.
                __throw_exception_again;
            }
        }

        template<typename _Tp>
        explicit __shared_count(std::auto_ptr<_Tp>& __r) : _M_pi(new _Sp_counted_base_impl<_Tp*, _Sp_deleter<_Tp>, _Lp >(__r.get(), _Sp_deleter<_Tp>()))
        { __r.release(); }

        explicit __shared_count(const __weak_count<_Lp>& __r);

        ~__shared_count() // nothrow
        {
            if (_M_pi != 0)
                _M_pi->_M_release();
        }

        __shared_count(const __shared_count& __r) : _M_pi(__r._M_pi) // nothrow
        {
            if (_M_pi != 0)
                _M_pi->_M_add_ref_copy();
        }

        __shared_count& operator=(const __shared_count& __r) // nothrow
        {
            _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
            if (__tmp != _M_pi)
            {
                if (__tmp != 0)
                    __tmp->_M_add_ref_copy();
                if (_M_pi != 0)
                    _M_pi->_M_release();
                _M_pi = __tmp;
            }
            return *this;
        }

        void _M_swap(__shared_count& __r) // nothrow
        {
            _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
            __r._M_pi = _M_pi;
            _M_pi = __tmp;
        }

        long _M_get_use_count() const // nothrow
        { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }

        bool _M_unique() const // nothrow
        { return this->_M_get_use_count() == 1; }

        friend inline bool operator==(const __shared_count& __a, const __shared_count& __b)
        { return __a._M_pi == __b._M_pi; }

        friend inline bool operator<(const __shared_count& __a, const __shared_count& __b)
        { return std::less<_Sp_counted_base<_Lp>*>()(__a._M_pi, __b._M_pi); }

        void* _M_get_deleter(const std::type_info& __ti) const
        { return _M_pi ? _M_pi->_M_get_deleter(__ti) : 0; }

    private:
        friend class __weak_count<_Lp>;

        _Sp_counted_base<_Lp>*  _M_pi;
};

template<_Lock_policy _Lp>
inline __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r) : _M_pi(__r._M_pi)
{
    if (_M_pi != 0)
        _M_pi->_M_add_ref_lock();
    else
        __throw_bad_weak_ptr();
}

__weak_count

template<_Lock_policy _Lp = __default_lock_policy>
class __weak_count
{
    public:
        __weak_count() : _M_pi(0) {}

        __weak_count(const __shared_count<_Lp>& __r) : _M_pi(__r._M_pi) // nothrow
        {
            if (_M_pi != 0)
                _M_pi->_M_weak_add_ref();
        }

        __weak_count(const __weak_count<_Lp>& __r) : _M_pi(__r._M_pi) // nothrow
        {
            if (_M_pi != 0)
                _M_pi->_M_weak_add_ref();
        }

        ~__weak_count() // nothrow
        {
            if (_M_pi != 0)
                _M_pi->_M_weak_release();
        }

        __weak_count<_Lp>& operator=(const __shared_count<_Lp>& __r) // nothrow
        {
            _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
            if (__tmp != 0)
                __tmp->_M_weak_add_ref();
            if (_M_pi != 0)
                _M_pi->_M_weak_release();
            _M_pi = __tmp;
            return *this;
        }

        __weak_count<_Lp>& operator=(const __weak_count<_Lp>& __r) // nothrow
        {
            _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
            if (__tmp != 0)
                __tmp->_M_weak_add_ref();
            if (_M_pi != 0)
                _M_pi->_M_weak_release();
            _M_pi = __tmp;
            return *this;
        }

        void _M_swap(__weak_count<_Lp>& __r) // nothrow
        {
            _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
            __r._M_pi = _M_pi;
            _M_pi = __tmp;
        }

        long _M_get_use_count() const // nothrow
        { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }

        friend inline bool operator==(const __weak_count<_Lp>& __a, const __weak_count<_Lp>& __b)
        { return __a._M_pi == __b._M_pi; }

        friend inline bool operator<(const __weak_count<_Lp>& __a, const __weak_count<_Lp>& __b)
        { return std::less<_Sp_counted_base<_Lp>*>()(__a._M_pi, __b._M_pi); }

    private:
        friend class __shared_count<_Lp>;

        _Sp_counted_base<_Lp>*  _M_pi;
};

__shared_ptr

template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr
{
    public:
        typedef _Tp   element_type;

        __shared_ptr() : _M_ptr(0), _M_refcount() // never throws
        { }

        template<typename _Tp1>
        explicit __shared_ptr(_Tp1* __p) : _M_ptr(__p), _M_refcount(__p)
        {
            __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
            typedef int _IsComplete[sizeof(_Tp1)];
            __enable_shared_from_this_helper(_M_refcount, __p, __p);
        }

        template<typename _Tp1, typename _Deleter>
        __shared_ptr(_Tp1* __p, _Deleter __d) : _M_ptr(__p), _M_refcount(__p, __d)
        {
            __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
            __enable_shared_from_this_helper(_M_refcount, __p, __p);
        }

        template<typename _Tp1>
        __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r) : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
        { __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) }

        template<typename _Tp1>
        explicit __shared_ptr(const __weak_ptr<_Tp1, _Lp>& __r) : _M_refcount(__r._M_refcount) // may throw
        {
            __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
        _M_ptr = __r._M_ptr;
        }

        template<typename _Tp1>
        __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, __static_cast_tag) : _M_ptr(static_cast<element_type*>(__r._M_ptr)),_M_refcount(__r._M_refcount)
        { }

        template<typename _Tp1>
        __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, __const_cast_tag) : _M_ptr(const_cast<element_type*>(__r._M_ptr)),_M_refcount(__r._M_refcount)
        { }

        template<typename _Tp1>
        __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, __dynamic_cast_tag) : _M_ptr(dynamic_cast<element_type*>(__r._M_ptr)),_M_refcount(__r._M_refcount)
        {
            if (_M_ptr == 0) // need to allocate new counter -- the cast failed
                _M_refcount = __shared_count<_Lp>();
        }

        template<typename _Tp1>
        __shared_ptr& operator=(const __shared_ptr<_Tp1, _Lp>& __r) // never throws
        {
            _M_ptr = __r._M_ptr;
            _M_refcount = __r._M_refcount; // __shared_count::op= doesn‘t throw
            return *this;
        }

        void reset() // never throws
        { __shared_ptr().swap(*this); }

        template<typename _Tp1>
        void reset(_Tp1* __p) // _Tp1 must be complete.
        {
            _GLIBCXX_DEBUG_ASSERT(__p == 0 || __p != _M_ptr);
            __shared_ptr(__p).swap(*this);
        }

        template<typename _Tp1, typename _Deleter>
        void reset(_Tp1* __p, _Deleter __d)
        { __shared_ptr(__p, __d).swap(*this); }

        typename std::tr1::add_reference<_Tp>::type operator*() const // never throws
        {
            _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
            return *_M_ptr;
        }

        _Tp* operator->() const // never throws
        {
            _GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
            return _M_ptr;
        }

        _Tp* get() const // never throws
        { return _M_ptr; }

    private:
        typedef _Tp* __shared_ptr::*__unspecified_bool_type;

    public:
        operator __unspecified_bool_type() const // never throws
        { return _M_ptr == 0 ? 0 : &__shared_ptr::_M_ptr; }

        bool unique() const // never throws
        { return _M_refcount._M_unique(); }

        long use_count() const // never throws
        { return _M_refcount._M_get_use_count(); }

        void swap(__shared_ptr<_Tp, _Lp>& __other) // never throws
        {
            std::swap(_M_ptr, __other._M_ptr);
            _M_refcount._M_swap(__other._M_refcount);
        }

    private:
        void* _M_get_deleter(const std::type_info& __ti) const
        { return _M_refcount._M_get_deleter(__ti); }

        template<typename _Tp1, _Lock_policy _Lp1>
        bool _M_less(const __shared_ptr<_Tp1, _Lp1>& __rhs) const
        { return _M_refcount < __rhs._M_refcount; }

        template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
        template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;

        template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
        friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&);

        template<typename _Tp1>
        friend inline bool operator==(const __shared_ptr& __a, const __shared_ptr<_Tp1, _Lp>& __b)
        { return __a.get() == __b.get(); }

        template<typename _Tp1>
        friend inline bool operator!=(const __shared_ptr& __a, const __shared_ptr<_Tp1, _Lp>& __b)
        { return __a.get() != __b.get(); }

        template<typename _Tp1>
        friend inline bool operator<(const __shared_ptr& __a, const __shared_ptr<_Tp1, _Lp>& __b)
        { return __a._M_less(__b); }

        _Tp*               _M_ptr;         // Contained pointer.
        __shared_count<_Lp>  _M_refcount;    // Reference counter.
};

template<typename _Tp, _Lock_policy _Lp>
inline void swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b)
{ __a.swap(__b); }

template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp> static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r)
{ return __shared_ptr<_Tp, _Lp>(__r, __static_cast_tag()); }

template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp> const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r)
{ return __shared_ptr<_Tp, _Lp>(__r, __const_cast_tag()); }

template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp> dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r)
{ return __shared_ptr<_Tp, _Lp>(__r, __dynamic_cast_tag()); }

template<typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp>
std::basic_ostream<_Ch, _Tr>& operator<<(std::basic_ostream<_Ch, _Tr>& __os, const __shared_ptr<_Tp, _Lp>& __p)
{
    __os << __p.get();
    return __os;
}

template<typename _Del, typename _Tp, _Lock_policy _Lp>
inline _Del* get_deleter(const __shared_ptr<_Tp, _Lp>& __p)
{return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del)));}

shared_ptr

template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
{
    public:
        shared_ptr() : __shared_ptr<_Tp>() { }

        template<typename _Tp1>
        explicit shared_ptr(_Tp1* __p) : __shared_ptr<_Tp>(__p) { }

        template<typename _Tp1, typename _Deleter>
        shared_ptr(_Tp1* __p, _Deleter __d) : __shared_ptr<_Tp>(__p, __d) { }

        template<typename _Tp1>
        shared_ptr(const shared_ptr<_Tp1>& __r) : __shared_ptr<_Tp>(__r) { }

        template<typename _Tp1>
        explicit shared_ptr(const weak_ptr<_Tp1>& __r) : __shared_ptr<_Tp>(__r) { }

        template<typename _Tp1>
        shared_ptr(const shared_ptr<_Tp1>& __r, __static_cast_tag) : __shared_ptr<_Tp>(__r, __static_cast_tag()) { }

        template<typename _Tp1>
        shared_ptr(const shared_ptr<_Tp1>& __r, __const_cast_tag) : __shared_ptr<_Tp>(__r, __const_cast_tag()) { }

        template<typename _Tp1>
        shared_ptr(const shared_ptr<_Tp1>& __r, __dynamic_cast_tag) : __shared_ptr<_Tp>(__r, __dynamic_cast_tag()) { }

        template<typename _Tp1>
        shared_ptr& operator=(const shared_ptr<_Tp1>& __r) // never throws
        {
            this->__shared_ptr<_Tp>::operator=(__r);
            return *this;
        }

};

template<typename _Tp>
inline void swap(__shared_ptr<_Tp>& __a, __shared_ptr<_Tp>& __b)
{ __a.swap(__b); }

template<typename _Tp, typename _Tp1>
inline shared_ptr<_Tp> static_pointer_cast(const shared_ptr<_Tp1>& __r)
{ return shared_ptr<_Tp>(__r, __static_cast_tag()); }

template<typename _Tp, typename _Tp1>
inline shared_ptr<_Tp> const_pointer_cast(const shared_ptr<_Tp1>& __r)
{ return shared_ptr<_Tp>(__r, __const_cast_tag()); }

template<typename _Tp, typename _Tp1>
inline shared_ptr<_Tp> dynamic_pointer_cast(const shared_ptr<_Tp1>& __r)
{ return shared_ptr<_Tp>(__r, __dynamic_cast_tag()); }

__weak_ptr

template<typename _Tp, _Lock_policy _Lp>
class __weak_ptr
{
    public:
        typedef _Tp element_type;

        __weak_ptr() : _M_ptr(0), _M_refcount() // never throws
        { }

        template<typename _Tp1>
        __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r) : _M_refcount(__r._M_refcount) // never throws
        {
            __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
            _M_ptr = __r.lock().get();
        }

        template<typename _Tp1>
        __weak_ptr(const __shared_ptr<_Tp1, _Lp>& __r) : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
        { __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) }

        template<typename _Tp1>
        __weak_ptr& operator=(const __weak_ptr<_Tp1, _Lp>& __r) // never throws
        {
            _M_ptr = __r.lock().get();
            _M_refcount = __r._M_refcount;
            return *this;
        }

        template<typename _Tp1>
        __weak_ptr& operator=(const __shared_ptr<_Tp1, _Lp>& __r) // never throws
        {
            _M_ptr = __r._M_ptr;
            _M_refcount = __r._M_refcount;
            return *this;
        }

        __shared_ptr<_Tp, _Lp>lock() const // never throws
        {
            return expired() ? __shared_ptr<element_type, _Lp>()
                     : __shared_ptr<element_type, _Lp>(*this);

        } // XXX MT

        long use_count() const // never throws
        { return _M_refcount._M_get_use_count(); }

        bool expired() const // never throws
        { return _M_refcount._M_get_use_count() == 0; }

        void reset() // never throws
        { __weak_ptr().swap(*this); }

        void swap(__weak_ptr& __s) // never throws
        {
            std::swap(_M_ptr, __s._M_ptr);
            _M_refcount._M_swap(__s._M_refcount);
        }

    private:
        void _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount)
        {
            _M_ptr = __ptr;
            _M_refcount = __refcount;
        }

        template<typename _Tp1>
        bool _M_less(const __weak_ptr<_Tp1, _Lp>& __rhs) const
        { return _M_refcount < __rhs._M_refcount; }

        template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
        template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
        friend class __enable_shared_from_this<_Tp, _Lp>;
        friend class enable_shared_from_this<_Tp>;

        template<typename _Tp1>
        friend inline bool operator<(const __weak_ptr& __lhs, const __weak_ptr<_Tp1, _Lp>& __rhs)
        { return __lhs._M_less(__rhs); }

        _Tp*         _M_ptr;         // Contained pointer.
        __weak_count<_Lp>  _M_refcount;    // Reference counter.
};

template<typename _Tp, _Lock_policy _Lp>
inline void swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b)
{ __a.swap(__b); }

weak_ptr

template<typename _Tp>
class weak_ptr : public __weak_ptr<_Tp>
{
    public:
        weak_ptr() : __weak_ptr<_Tp>() { }

        template<typename _Tp1>
        weak_ptr(const weak_ptr<_Tp1>& __r) : __weak_ptr<_Tp>(__r) { }

        template<typename _Tp1>
        weak_ptr(const shared_ptr<_Tp1>& __r) : __weak_ptr<_Tp>(__r) { }

        template<typename _Tp1>
        weak_ptr& operator=(const weak_ptr<_Tp1>& __r) // never throws
        {
            this->__weak_ptr<_Tp>::operator=(__r);
            return *this;
        }

        template<typename _Tp1>
        weak_ptr& operator=(const shared_ptr<_Tp1>& __r) // never throws
        {
            this->__weak_ptr<_Tp>::operator=(__r);
            return *this;
        }

        shared_ptr<_Tp> lock() const // never throws
        {
            return this->expired() ? shared_ptr<_Tp>() : shared_ptr<_Tp>(*this);
        }
};

类型声明

    struct __static_cast_tag { };
    struct __const_cast_tag { };
    struct __dynamic_cast_tag { };

    template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
    class __shared_ptr;

    template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
    class __weak_ptr;

    template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
    class __enable_shared_from_this;

    template<typename _Tp>
    class shared_ptr;

    template<typename _Tp>
    class weak_ptr;

    template<typename _Tp>
    class enable_shared_from_this;

继承关系


其中,很明显的可以看出,shared_ptr指向内部含有两个指针:指向被管理对象的指针一个指向管理对象基类的指针。其中,管理对象由具有原子属性的use_count和weak_count组成,指向被管理对象的T的指针以及用来销毁被管理对象的deleter指针。
被new创建的后托管给shared_ptr的指针称为被管理对象;智能指针内部创建的用来维护被管理对象生命周期的实例称作管理对象。

shared_ptr

创建shared_ptr的时候不但需要动态的在堆上创建一个被管理对象(_M_ptr),同样需要在堆上创建一个管理对象(_M_refcount):

template<typename _Tp1> explicit __shared_ptr(_Tp1* __p)
: _M_ptr(__p), _M_refcount(__p) {
    __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
    typedef int _IsComplete[sizeof(_Tp1)];
    __enable_shared_from_this_helper(_M_refcount, __p, __p);
}

template<typename _Ptr>
__shared_count(_Ptr __p) : _M_pi(0)
{
    __try
   {
      typedef typename std::tr1::remove_pointer<_Ptr>::type _Tp;
      _M_pi = new _Sp_counted_base_impl<_Ptr, _Sp_deleter<_Tp>, _Lp>(__p, _Sp_deleter<_Tp>());
    }
    __catch(...)
    {
        delete __p;
    __throw_exception_again;
    }
}

shared_ptr的内部包含一个指向被管理对象的指针(_M_ptr),_Sp_counted_base_impl中也存在一个指向被管理对象的指针(_M_ptr),为什么呢?让我们从shared_ptr的复制说起:

template<typename _Tp1>
 __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r)
 : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
{__glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)}

template<typename _Tp1>
__shared_ptr& operator=(const __shared_ptr<_Tp1, _Lp>& __r) // never throws
{
    _M_ptr = __r._M_ptr;
    _M_refcount = __r._M_refcount; // __shared_count::op= doesn‘t throw
    return *this;
}

__shared_count&
operator=(const __shared_count& __r) // nothrow
{
    _Sp_counted_base<_Lp>* __tmp = __r._M_pi;        //指向sp2的管理计数对象
    if (__tmp != _M_pi)
    {
        if (__tmp != 0)
            __tmp->_M_add_ref_copy();        //增加sp2的引用计数
    if (_M_pi != 0)
        _M_pi->_M_release();        //减少sp1的引用计数

        _M_pi = __tmp;        //令sp1的count指向sp2?有点多余啊
    }
    return *this;
}

根据上面描述的代码,考虑这种情形:sp1指向a1,sp2指向a2(a1 != a2)。当把sp1赋给sp2时,就会出现__tmp!= _M_pi的情况。假设,初始时有且仅有一个sp1指向a1,有且仅有一个sp2指向a2。指向代码:sp1 = sp2,当赋值结束时,sp1和sp2都指向a2,没有指针指向a1,sp1指向的a1及其对应的管理对象均应该被析构。在上面代码的描述中:首先获取sp2的_Sp_counted_base*指针,紧接着判断sp2的_Sp_counted_base与sp1的_Sp_counted_base是否相等,因为已经调整了sp2的指向,肯定是不相等的,于是,进入sp1的析构阶段。此时,__tmp描述的是sp2的指针,_M_pi描述的是sp1的指针。因为此时,sp1和sp2都指向同一个管理对象,增加sp2的管理计数,然后减少sp1的管理计数。最后,将sp1的管理对象指针指向sp2?有点多余啊。

//************_Sp_counted_base*****************//
void
_M_add_ref_copy()
{ __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }

//************_Sp_counted_base*****************//
void
_M_release() // nothrow
{
    // Be race-detector-friendly.  For more info see bits/c++config.
    _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
    {
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
        _M_dispose();

        if (_Mutex_base<_Lp>::_S_need_barriers)
        {
            __atomic_thread_fence (__ATOMIC_ACQ_REL);
        }

            // Be race-detector-friendly.  For more info see bits/c++config.
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
        if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
            {
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
            _M_destroy();
             }
    }
}

//************_Sp_counted_base*****************//
// Called when _M_use_count drops to zero, to release the resources
// managed by *this.
virtual void
_M_dispose() = 0; // nothrow

// Called when _M_weak_count drops to zero.
virtual void
_M_destroy() // nothrow
{ delete this; }

//************_Sp_counted_base_impl*************//
virtual void
_M_dispose() // nothrow
{ _M_del(_M_ptr); }

_M_release()函数首先对a1的use_count减去1,并对比减之前的值,如果减之前是1,说明减后是0,a1没有任何shared_ptr指针指向了,就应该将a1销毁了,于是调用_M_dispose()函数销毁a1;同时,应该对a1的weak_count减去1,并对比减之前的值,如果减之前是1,说明减之后是0,此时已经没有任何weak_ptr指针指向它了,应该将管理对象销毁,于是调用_M_destory()销毁管理对象。这就解释了为什么shared_ptr对象内部包含两指向被管理对象的指针了:**__shared_ptr直接包含的裸指针是为了实现向*,->之类的操作,通过__shared_count间接包含的指针是为了管理对象的生命周期,回收相关资源
同时,
__shared_count内部的use_count主要用来标记被管理对象的生命周期,weak_count主要用来标记管理对象的生命周期**
当一个shared_ptr超出作用域被销毁时,它会调用__shared_count的_M_release()对use_count和weak_count进行自减并判断是否需要释放管理对象和被管理对象:

~__shared_count() // nothrow
 {
     if (_M_pi != 0)
      _M_pi->_M_release();
 }

weak_ptr

对于weak_ptr,我们从其对应的__weak_count说起:

//************_Sp_counted_base*****************//
 void
 _M_weak_add_ref() // nothrow
{ __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }

//************_Sp_counted_base*****************//
void
_M_weak_release() // nothrow
{
    // Be race-detector-friendly. For more info see bits/c++config.
    _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
    {
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
    if (_Mutex_base<_Lp>::_S_need_barriers)
    {
        // See _M_release(),
        // destroy() must observe results of dispose()
            __atomic_thread_fence (__ATOMIC_ACQ_REL);
    }
    _M_destroy();
    }
}

__weak_count<_Lp>& operator=(const __shared_count<_Lp>& __r) // nothrow
{
    _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
    if (__tmp != 0)
        __tmp->_M_weak_add_ref();

    if (_M_pi != 0)
        _M_pi->_M_weak_release();

    _M_pi = __tmp;  

    return *this;
}

__weak_count<_Lp>& operator=(const __weak_count<_Lp>& __r) // nothrow
{
    _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
    if (__tmp != 0)
        __tmp->_M_weak_add_ref();
    if (_M_pi != 0)
        _M_pi->_M_weak_release();
    _M_pi = __tmp;

    return *this;
}

__weak_count<_Lp>& operator=(const __shared_count<_Lp>& __r) // nothrow
{
    _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
    if (__tmp != 0)
      __tmp->_M_weak_add_ref();
    if (_M_pi != 0)
      _M_pi->_M_weak_release();
    _M_pi = __tmp;
    return *this;
}

~__weak_count() // nothrow
{
    if (_M_pi != 0)
        _M_pi->_M_weak_release();
}

从上面可以看出:

  • __weak_count相关的复制拷贝以及析构函数只会影响到weak_count的值,对use_count没有影响;当weak_count为0时,释放管理对象。也就是说,**__weak_ptr不影响被管理对象的生命周期。同时,由于__weak_ptr没有像shared_ptr那样实现->,*之类的指针操作,__weak_ptr不能直接操作被管理的对象**。
  • __weak_count自身间的赋值以及__shared_count对__weak_count的赋值时,他们都具有相同的指向管理对象的指针;也就是说:**当多个__weak_ptr和__shared_ptr指向同一个管理对象时,他们共享同一个管理对象**,这就保证了可以通过__weak_ptr可以判断__shared_ptr指向的被管理对象是否存在以及获取到被管理对象的指针。
    __shared_ptr和__weak_ptr在管理同一对象时,他们之间的关系如下:

    由于weak_ptr不能直接操作被管理对象的但仍然持有指向被管理对象的指针(用来初始化内部的__weak_count对象),weak_ptr与被管理对象用虚线连接。
    同时,weak_ptr有几个重要的成员函数:
  • expired():判断该对象是否已经被释放
  • use_count():返回目前有多少个shared_ptr指向被管理的对象
  • lock():返回一个指向被管理对象的shared_ptr
/*************_weak_ptr*************************/
long
use_count() const // never throws
{ return _M_refcount._M_get_use_count(); }

bool
expired() const // never throws
{ return _M_refcount._M_get_use_count() == 0; }

 long
_M_get_use_count() const // nothrow
{ return const_cast<const volatile _Atomic_word&>(_M_use_count); }

__shared_ptr<_Tp, _Lp>
lock() const // never throws
{
#ifdef __GTHREADS
       // Optimization: avoid throw overhead.
    if (expired())
              return __shared_ptr<element_type, _Lp>();

    __try
    {
            return __shared_ptr<element_type, _Lp>(*this);
    }
    __catch(const bad_weak_ptr&)
    {
        // Q: How can we get here?
       // A: Another thread may have invalidated r after the
       //    use_count test above.
       return __shared_ptr<element_type, _Lp>();
     }

#else
    // Optimization: avoid try/catch overhead when single threaded.
    return expired() ? __shared_ptr<element_type, _Lp>()
                     : __shared_ptr<element_type, _Lp>(*this);

#endif
} // XXX MT

当然了,shared_ptr也会给在某些地方挖坑。在正常情况下,多个shared_ptr只用同一个管理对象管理同一个被管理对象。但是,在某些情况下,会出现多个管理对象管理同一个被管理对象的情况,这种情况下会出现double free的错误。在下面这种描述中,两个sp拥有不同的管理对象,但是指向了同一块堆内存,这就导致了sp1和sp2析构时会将被管理对象析构两次。

class Thing {
public:
    void foo();
    void defrangulate();
};

void transmogrify(shared_ptr<Thing>);

int main()
{
    shared_ptr<Thing> t1(new Thing); // create manager object A for the Thing
    t1->foo();
}

void Thing::foo()
{
    shared_ptr<Thing> sp_for_this(this);
    transmogrify(sp_for_this);
}

void transmogrify(shared_ptr<Thing> ptr)
{
    ptr->defrangulate();
}

怎么解决上述的问题:当一个对象M创建之后,如果一个函数foo的形参为M类型的智能指针,如何在对象M内部将对象M的指针作为实参传递给该函数foo呢?C++引入了enable_shared_from_this用weak_ptr的特性解决了这一问题。其基本思想是通过让M继承enable_shared_from_this,这样对象M的内部将会有一个__weak_shared指针_M__weak_this,在第一次创建指向M的shared_ptr sp的时候,通过模板特例化,将会初始化_M_weak_this;这样,M内部也会产生一个指向自身的weak_ptr,并且该weak_ptr内部的管理对象与sp的管理对象是相同的(这可以从weak_ptr年内不得_M_assign函数看出)。

// Friend of enable_shared_from_this.
template<typename _Tp1, typename _Tp2>
void __enable_shared_from_this_helper(const __shared_count<>&, const enable_shared_from_this<_Tp1>*, const _Tp2*);

template<typename _Tp1>
explicit __shared_ptr(_Tp1* __p)
: _M_ptr(__p), _M_refcount(__p)
{
    __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) typedef int _IsComplete[sizeof(_Tp1)];
    __enable_shared_from_this_helper(_M_refcount, __p, __p);

} 

template<typename _Tp>
class enable_shared_from_this
{
protected:
    enable_shared_from_this() { }

    enable_shared_from_this(const enable_shared_from_this&) { }

    enable_shared_from_this&
    operator=(const enable_shared_from_this&)
    { return *this; }

    ~enable_shared_from_this() { }

public:
    shared_ptr<_Tp>
    shared_from_this()
    { return shared_ptr<_Tp>(this->_M_weak_this); }

    shared_ptr<const _Tp>
    shared_from_this() const
    { return shared_ptr<const _Tp>(this->_M_weak_this); }

    private:
    template<typename _Tp1>
    void
    _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const
    { _M_weak_this._M_assign(__p, __n); }

    template<typename _Tp1>
    friend void
    __enable_shared_from_this_helper(const __shared_count<>& __pn, const enable_shared_from_this* __pe, const _Tp1* __px)
    {
    if (__pe != 0)
     __pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
    }

    mutable weak_ptr<_Tp>  _M_weak_this;
};

_M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount)
{
    _M_ptr = __ptr;
   _M_refcount = __refcount;
}

最后,在效率上需要注意一点:在采用shared_ptr<T> sp(new T)形式来创建sp管理对象时,将会出现两次堆内存分配:一是为被管理对象分配内存;二是为管理对象分配内存。怎么办呢?
可以采用shared_ptr<T> sp(make_shared<T>)的方式,采用这种方式将会一次分配一大块内存用于存放管理对象与被管理对象,这就避免了上面所说的二次内存分配的问题。
使用shared_ptr与weak_ptr时还需要注意一点:即使shared_ptr的use_count已经为0,被管理对象已经被析构,但是如果weak_ptr对象依旧存在,weak_count不为0,管理对象就不会被释放。

结论:

shared_ptr的引用计数是安全且无锁的,但对象的读写不是,因为shared_ptr有两个数据成员,读写操作不能原子化。即:

  • 一个shared_ptr对象实体可以被多个线程同时读取
  • 两个shared_ptr对象实体可以被两个线程同时写入,“析构算写操作”
  • 如果多个线程同时读取一个shared_ptr对象,需要加锁。

参考:
1.https://blog.csdn.net/ithiker/article/details/51532484
2.https://blog.csdn.net/Solstice/article/details/8547547

原文地址:https://www.cnblogs.com/xcb-1024day/p/11332478.html

时间: 2025-01-08 10:09:52

STL(五)之智能指针剖析的相关文章

【STL学习】智能指针之shared_ptr

前面已经学习过auto_ptr,这里补充另外一种智能指针,比auto_ptr要更强力更通用的shared_ptr. shared_ptr 简介及使用选择  几乎所有的程序都需要某种形式的引用计数智能指针,这种指针让我们不再需要为两个对象或更多对象共享的对象的生命周期而编写复杂的逻辑(写起来有点绕口),当被共享的对象引用计数降为0时,被共享对象被自动析构. 引用计数指针分为插入式(instrusive)和非插入式(non-instrusive)两种.前者要求它所管理的类提供明确的函数或数据成员用于

C++智能指针剖析(下)boost::shared_ptr&amp;其他

1. boost::shared_ptr 前面我已经讲解了两个比较简单的智能指针,它们都有各自的优缺点.由于 boost::scoped_ptr 独享所有权,当我们真真需要复制智能指针时,需求便满足不了了,如此我们再引入一个智能指针,专门用于处理复制,参数传递的情况,这便是如下的boost::shared_ptr. boost::shared_ptr 属于 boost 库,定义在 namespace boost 中,包含头文件#include<boost/smart_ptr.hpp> 便可以使

STL模板_智能指针概念

一.智能指针1.类类型对象,在其内部封装了一个普通指针.当智能指针对象因离开作用域而被析构时,其析构函数被执行,通过其内部封装的普通指针,销毁该指针的目标对象,避免内存泄露.2.为了表现出和普通指针一致的外观和行为,重载了解引用运算符(*)和间接成员访问运算符(->)函数,令其使用者可以将一个智能指针当成普通指针一样地使用.3.智能指针没有拷贝语义,只有转移语义,任何时候都只有一个智能指针对象持有真正的对象地址.4.智能指针不支持对象数组.二.模板的非类型参数1.无论是函数模板还是类模板,其模板

STL模板_multimap_智能指针作为键值

map的键值的类型 -可以是自定的类型(对象.函数指针.智能指针....) -但是有副作用-当自己定义的类型键值无法用系统自己提供的 < 或者 > 进行排序的时候,会出现各种问题 -所以需要自己定义比较器来进行处理 解决: -如果键值是对象类型 -可以自己在类中对 < 或者 > 运算符进行重载 -不需要对==进行重载 -因为元素的排序是根据<,和> 进行比较的 eg: -a > b 则 b <= a; -这边有点疑问..待补充.... class Key{

智能指针剖析

auto_ptr 已经废弃.原因是它行为上是"排它性"指针,但又允许编译器实现拷贝操作,拷贝后的右值会被赋空.即将"传递"语义掩盖在"拷贝"动作之下. 即a=b时,作为右值的b的物理指针会是NULL. 会造成使用它的容器混乱. 这是典型的设计缺陷.既然是"传递"语义,就不应以"拷贝"形式出现. 另一方面,它对于数组的指针也支持不好,无法完成new []和delete []的配对. unique_ptr 这是

(转)Delphi2009初体验 - 语言篇 - 智能指针(Smart Pointer)的实现

快速导航 一. 回顾历史二. 智能指针简介三. Delphi中的interface四. Delphi中智能指针的实现五. interface + 泛型 = 强类型的智能指针!六. 智能指针与集合七. 注意事项八. 总结 本随笔所有源代码打包下载 一.回顾历史 在c++中,对象可以创建在栈里,也可以创建在堆里.如: class CTestClass{public: CTestClass() { printf("Create"); } void DoPrint() {} ~CTestCla

C++智能指针类模板

1.智能指针本质上是一个对象,这个对象可以像原生的一样来进行使用.原因是智能指针对象对应的类中,将指针相关的操作都进行了重载操作处理,所以才会达到这种像是原生的效果. 2.智能指针的意义: 现在C++开发库中最重要的类模板之一 C++中自动内存管理的主要手段 能够在很大程度上避开内存相关的问题 3.在QT中开发库中也提供了智能指针类模板,在STL标准库中也提供了,在c++的标准库忘了什么名了中也提供了智能指针类模板.所以智能指针类模板在C++中的地位很重要 4.STL中的智能指针类模板 auto

C++的RAII和智能指针小结

RAII:资源分配即初始化,利用构造函数和析构函数定义一个类来完成对资源的分配和释放 智能指针主要用来防止内存泄漏,我们来举个栗子,看看为什么会有智能指针这个东东 例1: 对于上面这段程序,由于抛出异常的时候影响了代码的执行流,所以要在异常捕获之前将p提前释放(详见 我的博客:C++的异常浅析),虽然可以通过再次抛出以异常解决这个问题,但是在代码美观方面不够完 美,更重要的是如果在代码量非常大,而且在多处有动态开辟出来的空间的时候,仅仅通过再次抛出异常已 经远远不够解决这个问题了,会使得工作量大

第61课 智能指针类模板

1. 智能指针的意义 (1)现代C++开发库中最重要的类模板之一 (2)C++中自动内存管理的主要手段 (3)能够在很大程度上避开内存相关的问题(如内存泄漏.内存的多次释放等) 2. STL中的智能指针 (1)auto_ptr智能指针 ①生命周期结束时,销毁指向的内存空间 ②只能用来管理单个动态创建的对象,而不能管理动态创建的数组.即不能指向堆数组,只能指针堆对象(变量) int* pn = new int[100]; auto_ptr<int> ap(pn); //auto_ptr指向堆数组