对引用计数感到困惑

Confused about reference counting

本文关键字:引用      更新时间:2023-10-16

感谢您提前提供帮助。我正在读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根本不会改变。请纠正我!!再次感谢。

谨致问候。

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

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

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

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

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

然后还有使引用计数线程安全的问题。萨特对此写了大量的文章,参见第43条、第44条和第45条。

如果s1使用的引用计数为1,那么它将在字符串死亡时取下该字符串。考虑以下内容:

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

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

引用计数没有与每个对象关联。正如你从我给出的例子中看到的那样,这将是毫无价值的,因为引用计数永远不会作为安全清理的指标。

引用计数与这些对象共享的存储片段相关联对于s1s2,只有一个引用计数。这两个共享一个存储区,其中包含"更有效的C++"。这意味着有两个对该存储区的引用。两者中的每一个都需要知道有两个,这样它们就不会清理另一个正在使用的存储。

引用计数必须位于一个单独的共享内存中:

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

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