对引用计数感到困惑

时间:2012-07-15 23:29:34

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

感谢您提前帮助。 我正在阅读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。 我理解的是,由于复制构造函数是通过引用传递给const,在s2 = s1之后,s2.refCount将变为2,而s1.refCount将根本不会改变。 请纠正我!! 再次感谢。

最诚挚的问候。

5 个答案:

答案 0 :(得分:3)

在这种情况下,

value是一个指针,而const - ness不会传播到指向的对象,因此refCount 在此处是可变的。

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

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

然后存在使引用计数线程安全的问题。 Sutter对此进行了广泛的撰写,请参阅gotw #43gotw #44gotw #45

答案 1 :(得分:3)

  

我知道s2.refCount将变为2,而s1.refCount则不会发生变化。

有你的误解。没有s2.refCounts1.refCount这样的动物。相反,变量称为s2.value->refCounts1.value->refCount。请注意s2.value == s1.value,因此它们固有地共享相同的refCount成员。

答案 2 :(得分:1)

如果s1使用的引用计数为1,那么当它死亡时它将删除该字符串。请考虑以下事项:

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

在A点,s1死亡。如果其引用计数为1,则会清除与s2共享的存储空间,s2将使用无效存储空间。

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

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

答案 3 :(得分:0)

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

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.
};

答案 4 :(得分:0)

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