2015-12-14 34 views
2

我掃描shared_ptr實施GCC 5,我看到以下內容:GCC shared_ptr的拷貝賦值實施

__shared_ptr& 
    operator=(__shared_ptr&& __r) noexcept 
    { 
    __shared_ptr(std::move(__r)).swap(*this); 
    return *this; 
    } 

我的問題是,爲什麼交換前的臨時的額外舉措構建?我認爲編譯將消除任何額外的開銷 - 但爲什麼不只是撥打__r.swap(*this)?我錯過了一些聰明的副作用嗎?

我看到類中的其他函數也使用相同的模式實現,我可以理解接受const引用但接受右值引用的情況嗎?

回答

7

首先,這就是標準所說的,海灣合作委員會只是遵循這封信。

這樣,賦值運算符有一個後置條件,即__r.empty(),這將不會通過您的建議來實現,因此,如您所建議的那樣實施它將對標準說明有不同的影響,因此將不符合要求。

即這一說法成立:

auto p1 = std::make_shared<int>(1); 
auto p2 = std::make_shared<int>(2); 
p1 = std::move(p2); 
assert(!p2); 

的「聰明的副作用」是,你創建一個新的 shared_ptr的,這最終交換後舉行的*this舊值,然後熄滅的範圍。這意味着*this的舊值不會以__r結束。

+0

這是有道理的,這些天我應該停止拖延和掃描標準... – Nim

1

因爲我們需要調用一個引用右值的析構函數來減少實例數量。

1

通過將__r的內容移動到一個臨時文件中,並將其作爲函數return s銷燬,它確保移開的對象__r所指的內容處於空狀態。我想他們想把這個邏輯放在一個地方,移動構造函數,看起來像這樣。

__shared_ptr(__shared_ptr&& __r) noexcept 
    : _M_ptr(__r._M_ptr), _M_refcount() 
{ 
    _M_refcount._M_swap(__r._M_refcount); 
    __r._M_ptr = 0; 
} 

就我個人而言,我更喜歡下面的實現,據我所知,它是等價的。

widget& 
operator=(widget&& other) noexcept 
{ 
    widget temp {}; 
    swap(*this, temp); 
    swap(*this, other); 
    return *this; 
} 

它可以補充一個像這樣實現的移動構造函數。

widget(widget&& other) noexcept : widget {} 
{ 
    swap(*this, other); 
} 

我假設有一個

void 
swap(widget&, widget&) noexcept; 

重載ADL可以找到和的widget默認構造函數是noexcept

+0

Erm,你的實現說你必須默認構建一個'Widget'作爲做任務的一部分,並說你有移動/複製一個小部件的內容兩次? –

+0

@AndreKostur沒錯,只是它總是一個動作,從來沒有一個副本。 – 5gon12eder

+0

我同意,小部件本身會移動兩次,但是不支持移動的小部件的任何成員都會被複制兩次。 –

相關問題