2016-08-15 90 views
0

當您使用shared_ptr的複製分配操作符時,概念上,分配左側的shared_ptr需要遞減當前擁有的對象的引用計數,然後遞增分配右側對象的引用計數。 (假設,當然,這兩個指針非空。)shared_ptr分配:引用計數的順序

因此,一個實現可能看起來像下面的僞代碼:

shared_ptr& operator = (const shared_ptr& rhs) 
{ 
    decrement_reference_count(this->m_ptr); 
    this->m_ptr = rhs.m_ptr; 
    increment_reference_count(this->m_ptr); 
    return *this; 
} 

但需要注意的是,這裏我們遞減的this引用計數之前我們增加了參考計數rhs。我們也可以通過其他方式來做到這一點。我的問題是,標準是否確實在這裏指定了順序?

爲什麼它的確與衆不同:它可以使在事件差異有某種this引用計數和lhs引用計數之間的相關性。例如,假設兩者都是鏈接列表結構的一部分,其中每個鏈接節點中的next指針爲shared_ptr。因此,遞減結構中任何節點的引用計數可能會觸發析構函數,然後析構函數會引發連鎖反應並減少鏈中每個其他節點的引用計數(並可能會破壞)。

那麼,假設其中lhs引用計數是由this引用計數安全的情況下,它使一個很大的區別,如果我們第一遞減this,或者我們首先增加lhs。如果我們首先增加lhs之前遞減this,那麼我們可以確定lhs不會在我們遞減this時被銷燬。

但這是否標準實際上在這裏指定的順序?據我所看到的,標準說的唯一的事情是,拷貝賦值運算符是等效於表達式:

shared_ptr(lhs).swap(*this) 

但我真的不能換我的頭周圍的影響(如果有的話),這等效可能與遞減/增加參考計數的順序有關。

因此,沒有這裏的標準指定的訂單?或者是這個實現定義的行爲?

回答

1

它必須首先遞增基準計數器,萬一rhsthis。否則,當參考計數器爲1時,它可能會無意中銷燬指針。它可以檢查是否this == &rhs,但如果在減量之前執行參考計數器遞增,則不需要此檢查。

shared_ptr(lhs).swap(*this)因爲它首先創建一個副本,從而第一遞增引用計數器不從這個問題受到影響。

3

標準說[20.7.2.2。3]

shared_ptr& operator=(const shared_ptr& r) noexcept; 

具有等同於

shared_ptr(r).swap(*this) 

這意味着構建臨時,其中遞增的r引用計數,然後用*this交換其數據,然後破壞該臨時,這意味着遞減效果過去屬於*this的引用計數。