【问题标题】:boost shared_ptr cycling reference?提升 shared_ptr 循环参考?
【发布时间】:2013-04-24 05:51:22
【问题描述】:

来自 boost::shared_ptr 的 boost 文档:

由于实现使用引用计数,循环 shared_ptr 实例不会被回收。例如,如果 main() 持有一个 shared_ptr 到 A,它直接或间接持有一个 shared_ptr 回到 A,A 的使用计数将是 2。销毁 original shared_ptr 将留下 A 悬空,使用计数为 1。使用 weak_ptr 来“打破循环”。

我无法理解这一段,您能否提供一个关于这种情况的最小示例并解释其后果。

【问题讨论】:

    标签: boost shared-ptr smart-pointers cycle weak-ptr


    【解决方案1】:

    智能指针如何工作?他们记住指向对象的智能指针的count,并在新的共享指针控制对象时增加count,如果共享指针失去对对象的控制,则减少count

    假设你有一个班级:

    class A{
    public:
        A(){std::cout << "Object created" << std::endl;}
        ~A(){std::cout << "Object destroyed" << std::endl;}
        void setSibling(boost::shared_ptr<A> &sibling){
            m_sibling = sibling;
        }
    private:
        boots::shared_ptr<A> m_sibling;    
    };
    

    还有一个 foo():

    void foo(){
        //count increases from 0 to 1 (ptr take control on instance of A)
        boost::shared_ptr<A> ptr(new A); 
    
        //count increases from 1 to 2 (m_sibling take control on instanse of A)
        ptr->setSibling(ptr); 
    
        //count decreases from 2 to 1 
        //(ptr is destroyed and lose control on instance of A)
        return; 
    }
    

    当调用 ~A() 时 m_sibling 将失去控制,但只有当所有共享指针都失去控制时才会调用 ~A()。 因此,在调用 foo 之后,您将无法访问 A 的该实例。但是计数为 1,并且共享指针不会删除该对象,因此存在内存和资源泄漏。

    请参阅 boost 中 weak_ptr 的文档,了解如何将它们与 shared_ptr 一起使用。

    简而言之:弱指针类似于共享指针但不增加count。如果您有一个从shared_ptr 创建的weak_ptr 实例到被销毁的对象,如果您尝试访问原始指针,weak_prt 实例将抛出异常(不会发生段错误)。在 boost 文档中有一个示例如何使用 weak_ptr::lock() 方法正确使用 weak_prt

    【讨论】:

    • "智能指针是如何工作的?" 他们如何做什么他们做什么不是问题。
    【解决方案2】:

    想象一个宝藏。
    你的朋友拿了一个箱子,往里面放了一些金子。他还制作了一张地图。
    这是一张神奇的地图,只有一条:如果你烧掉最新的地图,宝藏和黄金都没有了。
    您的朋友将地图放在金币正上方的箱子中,为您制作第二张地图,然后将第一张地图放在里面。
    他给了你第二张地图,然后带着宝藏消失了。
    问题是:如果你烧掉你的地图会发生什么?
    答案:没什么,宝藏还在某处。

    为什么?因为最新的地图副本还在宝箱里!

    【讨论】:

      【解决方案3】:

      这是一个例子(注意~A 从未在这里被调用过):

      #include <boost/shared_ptr.hpp>
      #include <iostream>
      
      using boost::shared_ptr;
      struct A
      {
          ~A()
          {
              std::cout << "~A()" << std::endl;
          }
          void set_shared_ptr(const shared_ptr<A> &p)
          {
              p_ = p;
          }
          shared_ptr<A> p_;
      };
      
      int main()
      {
        shared_ptr<A> q(new A);
        q->set_shared_ptr(q);
        q.reset();
      }
      

      【讨论】:

        【解决方案4】:

        来自Boost documentation

        由于实现使用引用计数,循环 shared_ptr 实例不会被回收。

        你写:

        这一段我看不懂

        这很好;那是因为你很聪明。这一段毫无意义。如果你认为你明白了,那就意味着你没有。

        循环不能被回收,嗯,因为存在循环依赖!在循环的其余部分被回收之前,不能回收循环的任何部分,所以你必须销毁每个对象在它的毁灭开始之前。如果你有循环依赖,这是你的程序设计失败的一部分。不要试图责怪智能指针(或引用计数)。

        基本依赖问题的任何部分都与智能指针的实现细节没有任何关系; 这是由拥有智能指针的定义引起的:在(最后一个)拥有指针的析构函数开始运行之前,所拥有的对象不会被销毁。

        当然,对于像std::unique_ptr 这样甚至没有引用计数的独占所有权智能指针也是如此!

        使用weak_ptr“打破循环”。

        不要。避免循环。你不能“打破”一个循环。没有所谓的“打破”循环。

        Boost 的文档在这里比没用还糟糕。这很危险。它在这样一个级别上混合了不变量和实现,这表明对智能指针语义的理解非常糟糕。

        它说明了很多关于虚假信息和反模式自我复制的能力!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-03
          • 2018-10-01
          • 1970-01-01
          相关资源
          最近更新 更多