【问题标题】:Confused about reference counting对引用计数感到困惑
【发布时间】:2012-07-15 23:29:33
【问题描述】:

感谢您提前提供帮助。 我正在阅读 Scott Meyers 的《更有效的 C++》一书,但第 29 条“引用计数”中的一个简单程序确实让我感到困惑。 程序复制到这里:

String::String(const String& rhs): value(rhs.value) { ++value->refCount; }

然后代码:

String s1("More Effective C++");
String s2=s1;

我真的很困惑为什么 s1 和 s2 都会有一个 refCount 2。 我的理解是,由于复制构造函数是通过引用传递到常量,在 s2=s1,s2.refCount 将变为 2,而 s1.refCount 根本不会改变。 请纠正我!! 再次感谢。

最好的问候。

【问题讨论】:

    标签: c++ reference effective-c++


    【解决方案1】:

    我知道s2.refCount会变成2,而s1.refCount根本不会改变。

    这是你的误会。没有像s2.refCounts1.refCount 这样的动物。相反,这些变量称为s2.value->refCounts1.value->refCount。请注意s2.value == s1.value,因此它们本质上共享相同的refCount 成员。

    【讨论】:

      【解决方案2】:

      value 在这种情况下是一个指针,const-ness 不会传播到被指向的对象,所以 refCount 在这里是可变的。

      引用计数的目的是共享相同的对象表示而不重新创建它,直到所有引用消失,即引用计数降至零。此时,表示被解除分配。

      这对于只读对象非常有效,因此如果其中一个引用实例想要更改该共享表示,通常会克隆它并从一个重新开始引用计数。

      然后,使引用计数线程安全存在问题。 Sutter 对此写了大量文章,请参阅 gotw #43gotw #44gotw #45

      【讨论】:

        【解决方案3】:

        如果s1 使用的引用计数为1,那么它会在它死亡时将字符串连同它一起删除。考虑以下几点:

        String s2;
        {
            String s1("More Effective C++");
            s2 = s1;
        } // A
        

        在 A 点,s1 死亡。如果它的 refcount 为 1,它将清理它与 s2 共享的存储空间,而 s2 将使用无效存储空间。

        引用计数不与每个对象相关联。正如您从我给出的示例中看到的那样,这将毫无价值,因为引用计数永远不会作为可以安全清理的指标而值得信赖。

        引用计数与这些对象共享的存储块相关联。 s1s2 只有一个引用计数。两者共享一块存储,其中包含“更有效的 C++”。这意味着该存储有两个引用。两者中的每一个都需要知道有两个,这样他们就不会清理对方正在使用的存储空间。

        【讨论】:

          【解决方案4】:

          引用计数必须驻留在单独的共享内存中:

          struct Foo
          {
              unsigned int * refcount;      // shared among all "equal" objects!
          
              Foo() : refcount(new auto {1U}) { }
          
              Foo(Foo const & rhs) : refcount(rhs.refcount) { ++*refcount; }
          
              ~Foo() { --*refcount; if (*refcount == 0) { delete refcount; } }
          
              Foo & operator=(Foo const & rhs)
              {
                  if (this == std::addressof(rhs)) { return *this; }
                  --*refcount;
                  if (*refcount == 0) { delete refcount; }
                  refcount = rhs.refcount;
                  ++*refcount;
                  return *this;
              }
          
              // etc.
          };
          

          【讨论】:

          • 我很高兴你的例子 Foo 没有实际的资源可以分享。这将使这个赋值运算符看起来很简单。 ;)
          【解决方案5】:

          value 是一个指向底层实现结构的指针。字符串复制构造函数将指针复制到新对象 (s2) 中并增加指向实现结构的引用计数。但是,请记住原始对象 (s1) 具有相同的指针,因此从 s1 中看到的引用计数也将增加。只有一个底层实现结构,因此从一个 String 对象对其进行操作会影响共享该实现结构的所有其他 String 对象。这就是引用计数的全部意义所在!

          【讨论】:

            猜你喜欢
            • 2012-04-08
            • 1970-01-01
            • 2015-10-19
            • 1970-01-01
            • 1970-01-01
            • 2012-07-12
            • 2021-12-31
            • 2021-11-28
            相关资源
            最近更新 更多