2012-07-15 123 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對象。這是計算參考的整點!