代码之家  ›  专栏  ›  技术社区  ›  Troskyvs

如何证明c++11 make_shared()即使在dtor之后也能保持shared_ptr的控制块的活力?

  •  0
  • Troskyvs  · 技术社区  · 4 年前

    我的问题是:是否存在share_ptr引用计数为0,而weak_ptr引用数为 0?

    Difference in make_shared and normal shared_ptr in C++

    引用此线程,显示如果shared_ptr是由 make_shared 还有weak_ptr,它的控制块将是活动的 until sharedptr和weak_ptr的ref计数都为0。上面写着:

    weak_ptrs必须有一种方法来确定托管对象是否仍然有效(例如,对于锁)。他们通过检查拥有托管对象的shared_ptr的数量来实现这一点,托管对象存储在控制块中。结果是控制块是活动的,直到shared_ptr计数和weak_ptr计数都达到0。


    我做了一个快速测试。我希望 shared_ptr 创建者 生成共享 ,如果有weak_ptr指向它,它 control block 在shared_ptr被破坏后仍将持有某事物。

    #include<memory>
    #include<iostream>
    using namespace std;
    struct My {
        int m_i;
        My(int i) : m_i(i) { cout << "My ctor:" << m_i << '\n';}
        ~My() { cout << "My ctor:" << m_i << '\n';}
    };
    weak_ptr<My> wp1, wp2;
    int main() {
        {
            auto sp1 = shared_ptr<My>(new My(30));
            wp1 = weak_ptr<My>(sp1);
        }
        cout<< wp1.use_count() << endl;
        {
            auto sp2 = make_shared<My>(40);
            wp2 = weak_ptr<My>(sp2);
        }
        cout<< wp2.use_count() << endl;
        return 0;
    }
    

    二者都 use_count 将打印 0 ,我的程序似乎没有显示 control blocks 是否活着。

    那么,我们如何证明 The result is that the control blocks are alive until both shared_ptr and weak_ptr's ref count gets 0 ?

    有任何可以测试/证明这一理论的示例代码吗?

    1 回复  |  直到 4 年前
        1
  •  5
  •   Nicol Bolas    4 年前

    这不是一个需要“证明”的“理论”。这是真的 法令 ;该标准要求 weak_ptr 知道什么时候 shared_ptr 与它们相关的被销毁。这是由于 weak_ptr::lock 实现这一点的唯一可行方法(在不违反线程安全保证或以极其糟糕的方式提供线程安全保证的情况下)是拥有一块由弱指针和共享指针所有的内存,只有在所有指针都被破坏时才会处理。

    如果您希望看到演示,可以通过 shared_ptr 的构造函数是用户定义的分配器类型。 shared_ptr 将使用它为 shared_ptr 。只有当最后一个共享指针或弱指针被破坏时,控制块才会被删除。你也可以这样做 allocate_shared

        2
  •  1
  •   Jamishon    4 年前

    您的代码无法证明,因为sp1和sp2是局部变量,当它们超出范围时,它们将被释放。你可以用勾手或蛙跳来展示你想要看到的结果,但这并不容易。 我们可以阅读weak_ptr的源代码,这样我们就可以知道真正的作用,weak_ptr的源代码太多了,我们只查看关键部分:

      // The actual weak_ptr, with forwarding constructors and
      // assignment operators.
      template<typename _Tp>
        class weak_ptr
        : public __weak_ptr<_Tp>
        {
         
        };
    

    从代码中,我们可以看到大多数工作都是由父类__weak_ptr完成的,也就是说查看__weak_ptr的代码:

    template<typename _Tp, _Lock_policy _Lp>
        class __weak_ptr
        {
        public:
          
          
          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*>) }
     
     
          long
          use_count() const // never throws
          { return _M_refcount._M_get_use_count(); }
     
        
          _Tp*            _M_ptr;         // Contained pointer.
          __weak_count<_Lp>  _M_refcount;    // Reference counter.
        };
    

    当我们调用weak_ptr的use_count()时,我们调用_M_refcount_M_get_use_count(),_M_refcount是在类__weak_ptr的构造函数中分配的,在分配列表中我们可以看到_M_refcunt(__r._M_refccount),所以我们应该知道__weak_count的构造函数中真正的作用:

    template<_Lock_policy _Lp>
        class __weak_count
        {
        public:
          
          __weak_count(const __shared_count<_Lp>& __r)
          : _M_pi(__r._M_pi) // nothrow
          {
        if (_M_pi != 0)
          _M_pi->_M_weak_add_ref();
          }
          
        
          long
          _M_get_use_count() const // nothrow
          { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }
     
        
        private:
          friend class __shared_count<_Lp>;
     
          _Sp_counted_base<_Lp>*  _M_pi;
        };
    

    在类__weak_count的构造函数中,成员_M_pi是由shared_ptr的成员_M_pi分配的,我们查看函数_M_get_use_count(),当我们调用weak_ptr的use_count(。

    让我们回到您的问题:“是否存在share_ptr ref计数为0,而weak_ptr ref数不为0的情况?”

    我认为用正常的方式写代码,答案是否定的!

    推荐文章