2012-07-15 75 views
4

感谢您的帮助。 我正在阅读Scott Meyers的“更有效的C++”一书,但项目29“Reference Counting”中的一个简单程序真的让我困惑。 该计划是在这里复制:对引用计数感到困惑

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

然后代码:

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

我真的很困惑,为什么S1和S2都将有一个引用计数2. 我的理解是,既然副本构造函数是通过引用传递给const,在s2 = s1之后,s2.refCount将变为2,而s1.refCount根本不会改变。 请纠正我! 再次感谢。

最好的问候。

回答

1

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

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

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

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

引用计数与这些对象共享的存储块相关联。 对于s1s2,只有一个参考计数。这两个人共享一个“更有效的C++”存储。这意味着有两个存储引用。两者中的每一个都需要知道有两个,以便它们不会清理另一个正在使用的存储。

3

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

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

这对于只读对象很有用,所以如果其中一个引用实例想要更改该共享表示,它通常会被克隆并重新计数。

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

3

据我所知,s2.refCount将成为2,而s1.refCount将不会改变。

有您的误解。没有像s2.refCounts1.refCount这样的动物。相反,这些变量被称为s2.value->refCounts1.value->refCount。请注意,s2.value == s1.value,所以它们天生共享相同的refCount成员。

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

我很高兴你的例子'Foo'没有实际的资源可以共享。这会让这个赋值运算符看起来很简单。 ;) – 2012-07-15 23:41:13

0

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