4

感谢您提前提供帮助。我正在阅读 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。我的理解是,由于复制构造函数是 pass-by-reference-to-const,在 s2=s1,s2.refCount 将变为 2,而 s1.refCount 将变为 2。 refCount 根本不会改变。请纠正我!!再次感谢。

此致。

4

5 回答 5

3

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

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

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

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

于 2012-07-15T23:34:24.403 回答
3

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

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

于 2012-07-15T23:35:17.460 回答
1

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

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

在A点,s1死亡。如果它的 refcount 是 1,它会清理它共享的存储空间s2,并且s2会使用无效的存储空间。

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

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

于 2012-07-15T23:33:14.993 回答
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.
};
于 2012-07-15T23:35:25.963 回答
0

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

于 2012-07-15T23:37:58.567 回答