当前位置:   article > 正文

shared_ptr的内部实现原理_shared_ptr 原理

shared_ptr 原理

    本文先分析shared_ptr的内部实现原理,然后实例演示shared_ptr的使用。

1. 实现原理

    shared_ptr的定义如下:

  1. template<class _Ty>
  2. class shared_ptr : public _Ptr_base<_Ty>

    shared_ptr从基类_Ptr_base 继承了如下成员变量(部分源码):

  1. template<class _Ty>
  2. class _Ptr_base
  3. {
  4. private:
  5. element_type * _Ptr{ nullptr }; //指向资源
  6. _Ref_count_base * _Rep{ nullptr }; //指向资源引用计数
  7. }

   其中,_Ptr指向资源,_Rep指向资源引用计数。

    _Ref_count_base的定义如下:

  1. class __declspec(novtable) _Ref_count_base
  2. { // common code for reference counting
  3. private:
  4. _Atomic_counter_t _Uses; //记录了引用资源的shared_ptr的个数
  5. _Atomic_counter_t _Weaks; //记录了weak_ptr的个数
  6. }

    其中,Uses记录了资源的引用计数,也就是引用资源的shared_ptr 的个数;_Weaks记录了weak_ptr的个数,相当于资源观察者的个数。

    shared_ptr的构造函数定义如下:

  1. template<class _Ux,
  2. enable_if_t<conjunction_v<conditional_t<is_array_v<_Ty>, _Can_array_delete<_Ux>, _Can_scalar_delete<_Ux>>,
  3. _SP_convertible<_Ux, _Ty>>, int> = 0>
  4. explicit shared_ptr(_Ux * _Px)
  5. { // construct shared_ptr object that owns _Px
  6. _Setp(_Px, is_array<_Ty>{});
  7. }
  8. template<class _Ux>
  9. void _Setp(_Ux * _Px, false_type)
  10. { // take ownership of _Px
  11. _TRY_BEGIN // allocate control block and set
  12. _Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ux>(_Px));
  13. _CATCH_ALL // allocation failed, delete resource
  14. delete _Px;
  15. _RERAISE;
  16. _CATCH_END
  17. }

    shared_ptr的构造函数中会开辟新的引用计数的资源

    shared_ptr的拷贝构造函数定义如下:

  1. shared_ptr(const shared_ptr& _Other) noexcept
  2. { // construct shared_ptr object that owns same resource as _Other
  3. this->_Copy_construct_from(_Other);
  4. }
  5. template<class _Ty2>
  6. void _Copy_construct_from(const shared_ptr<_Ty2>& _Other)
  7. { // implement shared_ptr's (converting) copy ctor
  8. if (_Other._Rep)
  9. {
  10. _Other._Rep->_Incref();
  11. }
  12. _Ptr = _Other._Ptr;
  13. _Rep = _Other._Rep;
  14. }

    shared_ptr的拷贝构造函数没有开辟新的引用计数的资源,只是引用计数加1。

2.代码实例    

    先看下面出错的例子:

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. int main()
  5. {
  6. // 裸指针指向堆上的对象
  7. int *p = new int;
  8. shared_ptr<int> ptr1(p);
  9. shared_ptr<int> ptr2(p);
  10. //两次打印都是1,析构两次,出错
  11. cout << "use_count = " << ptr1.use_count() << endl;
  12. cout << "use_count = " << ptr2.use_count() << endl;
  13. getchar();
  14. return 0;
  15. }

    执行结果:

  

    原因:ptr1(p) 和 ptr2(p)都调用了shared_ptr的构造函数,它们管理同一个资源,但是重新开辟了引用计数的资源。所以引用计数都为1。析构函数会被调用两次,所以程序出错。

    正确的代码如下:

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. int main()
  5. {
  6. // 裸指针指向堆上的对象
  7. int *p = new int;
  8. shared_ptr<int> ptr1(p);
  9. shared_ptr<int> ptr2(ptr1);
  10. //两次打印都是2,析构一次,正确
  11. cout << "use_count = " << ptr1.use_count() << endl;
  12. cout << "use_count = " << ptr2.use_count() << endl;
  13. getchar();
  14. return 0;
  15. }

    执行结果:

    原因:ptr1(p) 调用构造函数,ptr2(ptr1)调用拷贝构造函数(没有开辟新的引用计数的资源,只是引用计数加1)。析构函数会被调用一次,所以程序正确。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/206278
推荐阅读
相关标签
  

闽ICP备14008679号