• shared_ptr & weak_ptr 源码分析


    shared_ptr & weak_ptr

    本次源码采用的是vs2015 c++11的源码进行分析

    sizeof(shard_ptr)=?

    回答这个问题,就需要看shared_ptr 的数据结构,下边进行源码分析

    shared_ptr

    C++
    template
            class shared_ptr
                    : public _Ptr_base<_Ty>
                   

    _Ptr_base<_Ty>

    C++
    template
    class _Ptr_base
    {        // base class for shared_ptr and weak_ptr
    public:
            typedef _Ptr_base<_Ty> _Myt;
            typedef _Ty element_type;
    private:
            _Ty *_Ptr;
            _Ref_count_base *_Rep;
     }

    也就是说 shared_ptr 内部数据就是两个指针_Ptr 与 _Rep

    那就很好理解了,在32位字节上4字节对齐情况下是8个字节

    在64位机器上,8字节对齐请下是16个字节

    shared_ptr 引用计数为0的时候做了什么

    shared_ptr::_Reset0

    C++
    template
            class shared_ptr
                    : public _Ptr_base<_Ty>
     {
                     void _Reset()
                    {        // release resource
                        _Reset(0, 0);
                    }

                    template
                    void _Reset(const _Ptr_base<_Ty2>& _Other)
                    {        // release resource and take ownership of _Other._Ptr
                        _Reset(_Other._Ptr, _Other._Rep);
                    }

                    template
                    void _Reset(const _Ptr_base<_Ty2>& _Other, bool _Throw)
                    {        // release resource and take ownership from weak_ptr _Other._Ptr
                        _Reset(_Other._Ptr, _Other._Rep, _Throw);
                    }
                        template
                        void _Reset(auto_ptr<_Ty2>&& _Other)
                        {        // release resource and take _Other.get()
                            _Ty2 *_Px = _Other.get();
                            _Reset0(_Px, new _Ref_count<_Ty>(_Px));
                            _Other.release();
                            _Enable_shared(_Px, _Rep);
                        }
                             void _Reset0(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)
                            {        // release resource and take new resource
                                if (_Rep != 0)
                                        _Rep->_Decref();
                                _Rep = _Other_rep;
                                _Ptr = _Other_ptr;
                            }
                           
     }
     

    _Ref_count_base::_Decref

    C++
    class _Ref_count_base
    {
         // common code for reference counting
        _Atomic_counter_t _Uses;
        _Atomic_counter_t _Weaks;
        void _Decref()
        {        // decrement use count
                if (_MT_DECR(_Uses) == 0)
                {        // destroy managed resource, decrement weak reference count
                    _Destroy();
                    _Decwref();
                }
        }
        virtual void _Delete_this() = 0;
            virtual void _Destroy() _NOEXCEPT
            {        // destroy managed resource
                delete _Ptr;
            }
            void _Decwref()
            {        // decrement weak reference count
                if (_MT_DECR(_Weaks) == 0)
                    _Delete_this();
            }
    };

    _Ref_count_del::_Delete_this

    C++
    template         class _Dx>
            class _Ref_count_del
            : public _Ref_count_base
            {        // handle reference counting for object with deleter
    public:
            _Ref_count_del(_Ty *_Px, _Dx _Dt)
                    : _Ref_count_base(), _Mypair(_One_then_variadic_args_t(), _Dt, _Px)
                    {        // construct
                    }

            virtual void *_Get_deleter(
                    const _XSTD2 type_info& _Typeid) const _NOEXCEPT
                    {        // return address of deleter object
                    return ((void *)(_Typeid == typeid(_Dx)
                            ? _STD addressof(_Mypair._Get_first()) : 0));
                    }

    private:
            virtual void _Destroy() _NOEXCEPT
                    {       
                    // _Get_first 拿到的是自定义析构方法
                    //_Mypair._Get_second() 管理的指针
                    _Mypair._Get_first()(_Mypair._Get_second());
                    }

            virtual void _Delete_this() _NOEXCEPT
                    {        // destroy self
                    delete this;
                    }

            _Compressed_pair<_Dx, _Ty *> _Mypair;
            };

    _Ref_count::_Delete_this

    C++
    template
            class _Ref_count
            : public _Ref_count_base
            {        // handle reference counting for object without deleter
    public:
            _Ref_count(_Ty *_Px)
                    : _Ref_count_base(), _Ptr(_Px)
                    {        // construct
                    }

    private:
            virtual void _Destroy() _NOEXCEPT
                    {        // destroy managed resource
                    delete _Ptr;
                    }

            virtual void _Delete_this() _NOEXCEPT
                    {        // destroy self
                    delete this;
                    }

            _Ty * _Ptr;
            };
     

    当shared ptr 创时候带了自定义析构函数会使用_Ref_count_del这个类

    默认使用的是_Delete_this

    通过上边分析可以看出,当智能指针的引用计数清0的时候首先会销毁ptr,其次在判断弱引用的技术是否也清0了,如果清0了就一并释放了

    weak_ptr 分析

    weak_ptr构造

    C++
    template
            class weak_ptr
                    : public _Ptr_base<_Ty>
            {        // class for pointer to reference counted resource
    public:
            typedef weak_ptr<_Ty> _Myt;
            typedef _Ptr_base<_Ty> _Mybase;

            constexpr 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);
            }
            //is_convertible 会判断原weak_ptr持有的指针跟构造的指针是否同一个类型
            //如果是同一个类型使用下边方法,不是会调用其他的构造芳芳
            //这也就是SFINAE典型应用
            template                 class = typename enable_if::value,
                            void>::type>
            weak_ptr(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
            {        // construct weak_ptr object for resource owned by _Other
                this->_Resetw(_Other);
            }  
      }

    通过shared_ptr构造weak_ptr 过程

    _Ptr_base::_Resetw

    C++
    template
    class _Ptr_base
    {        // base class for shared_ptr and weak_ptr
        void _Resetw()
        {        // release weak reference to resource
            _Resetw((_Ty *)0, 0);
        }
           
       template
        void _Resetw(const _Ptr_base<_Ty2>& _Other)
        {        // release weak reference to resource and take _Other._Ptr
            _Resetw(_Other._Ptr, _Other._Rep);
        }
        template
        void _Resetw(_Ty2 *_Other_ptr, _Ref_count_base *_Other_rep)
        {        // point to _Other_ptr through _Other_rep
            if (_Other_rep)
                    _Other_rep->_Incwref();
            if (_Rep != 0)
                    _Rep->_Decwref();
            _Rep = _Other_rep;
            _Ptr = const_cast *>(_Other_ptr);
        }
    public:
            typedef _Ptr_base<_Ty> _Myt;
            typedef _Ty element_type;
    private:
            _Ty *_Ptr;
            _Ref_count_base *_Rep;
           
     }

    通过上边的_Resetw 可以发现 它是从shared_ptr中的_Ptr与_Rep 构建出来的,为了防止构建过程中出现野指针的情况,它以上来就会调用_Other_rep->_Incwref();增加一个引用计数

    std::enable_shared_from_this

    enable_shared_from_this 定义

    C++
    template
            class enable_shared_from_this
            {        // provide member functions that create shared_ptr to this
    public:
            typedef _Ty _EStype;

            shared_ptr<_Ty> shared_from_this()
                    {        // return shared_ptr
                    return (shared_ptr<_Ty>(_Wptr));
                    }

            shared_ptr shared_from_this() const
                    {        // return shared_ptr
                    return (shared_ptr(_Wptr));
                    }
     private:
       
            weak_ptr<_Ty> _Wptr;
    }

  • 相关阅读:
    计算机二级WPS 选择题(模拟和解析五)
    Java---Stream流详解
    el-table表格设置——动态修改表头
    脚本之美│VBS 入门交互实战
    上线不到两个月,昇腾AI助推“中国算力网”再添新节点
    IIS发布网站,使用localhost无法调用Post、Put、Delete接口
    力扣名企直通车-学习计划-网易-刷题记录
    读书笔记-《ON JAVA 中文版》-摘要26[第二十三章 注解]
    Web Worker实现前端的“多线程”
    一文看懂个税2022
  • 原文地址:https://blog.csdn.net/c553110519/article/details/126278745