2012-11-15 33 views
6

another question讀到實現移動構造函數時,它是很好的做法,標準::移動每個成員在初始化列表中,因爲如果該成員恰好是另一個對象則是對象移動的構造將被調用。是這樣的...的std ::移動賦值運算符中移動

//Move constructor 
Car::Car(Car && obj) 
    : 
    prBufferLength(std::move(obj.prBufferLength)), 
    prBuffer(std::move(obj.prBuffer)) 
{ 
    obj.prBuffer = nullptr; 
    obj.prBufferLength = 0; 
} 

然而,在所有的樣品移動賦值運算符我見過,一直使用std ::此舉出於同樣的原因隻字不提。如果該成員是一個對象,那麼應該使用std :: move嗎?是這樣的...

//Move assignment 
Car Car::operator=(Car && obj) 
{ 
    delete[] prBuffer; 

    prBufferLength = std::move(obj.prBufferLength); 
    prBuffer = std::move(obj.prBuffer); 

    obj.prBuffer = nullptr; 
    obj.prBufferLength = 0; 
    return *this; 
} 

UPDATE:

我明白沒有必要在我所選擇的例子使用std ::移動(不好)但我感興趣的是,如果會員是對象。

+0

我當然也對這一點做了一些澄清。 – goji

+1

'我在另一個問題中讀到',你能否鏈接那個問題?在你的例子中沒有理由使用'std :: move'。 –

+0

@JesseGood見編輯,謝謝 – TomP89

回答

3

在閱讀鏈接的問題後,我可以看到第二個最常見的答案是在移動構造函數的初始化程序列表中使用std::move,因爲無論它是否爲基本類型,它都會執行正確的事。我有點不同意,並認爲你應該只在適當時打電話std::move,但這是個人喜好進來。

另外,對於你的移動賦值運算符,你有它的方式是好的,雖然我認爲不必要的呼叫個人應該刪除std::move。另一種選擇是使用std::swap這將爲你做正確的事情。

Car Car::operator=(Car && obj) 
{ 
    std::swap(this->prBufferLength, obj.prBufferLength); 
    std::swap(this->prBuffer, obj.prBuffer); 
    return *this; 
} 

上述舉動賦值運算符和您的移動賦值運算符之間的區別在於內存的釋放是延遲,而你的版本會釋放內存向右走,這可能是在某些情況下非常重要。

+1

'swap'將不會在這裏做正確的事情 - 移動的對象在這裏可能會非常沉重,這違反了最不讓人驚訝的原則。 – ildjarn

+0

@ildjarn:有趣的一點。但是,既然說從對象轉移了一個「有效但未具體說明的狀態」,我認爲這違反了最不讓人意外的原則。 –

+0

作爲標準慣例,如果標準容器對象的實例化在從標準容器中移出時不會變爲空,那麼我肯定會發現它令人驚訝。也就是說,與通常情況不同的是,我不是從標準的角度來做這個表述,而是從已經確定的實踐(meh)的角度來做這個表述。 – ildjarn

1

它看起來像prBuffer是一個指針,prBufferLength是某種整數類型,所以move是不會做出這種特殊情況下的任何區別,因爲它們都是基本類型。

例如,如果prBufferstd::string例如,那麼您應該使用move強制使用移動構造函數或移動賦值運算符。

+0

對不起,我應該在問題中提到我目前正在使用基本類型,謝謝澄清 – TomP89

1

就象在C中的很多東西++和生活有沒有一個明確的是或否的答案的問題。

也就是說,如果傳入成員將被清除/重置/清空並將傳入成員分配給目標成員將導致調用操作員被調用,那麼您將希望使用std :: move移動賦值運算符將被調用,而不是複製賦值運算符。

如果賦值運算符將不會被調用(即只是一個淺拷貝會做),然後使用std ::舉動是沒有必要的。

0

我相信(的?)更好地實現移動分配的方式是使用移動構造函數創建一個新的臨時對象,然後與當前對象調換它,就像拷貝賦值。

它不僅避免了重複代碼,也可以防止您通過例如犯錯誤意外忘記移動會員。

+0

複製和交換是實現複製構造函數的方式。移動構造函數應該簡單地交換,不需要臨時的。 –

+0

@MooingDuck:好的,我應該在這之前三思而後行! – Mehrdad

+0

呃,@MooingDuck,你如何使用副本和任何東西來實現複製構造?這個副本是什麼?我認爲你的意思是複製和交換是實現副本_assignment_的好方法,這就是Mehrdad首先說的,同時談論移動分配而不是移動構造函數。 –

1

如果你的成員對象將移動受益,你當然應該移動它們。在你所連接的答案中證明的另一種策略是交換。交換就像是在移動,但它正在向兩個方向移動。如果你的類管理的資源,這有一個在(右值)傳遞的對象recieving的不再想數據的影響。該數據然後被該對象的析構函數銷燬。例如,你的舉動賦值運算符可以這樣寫:

Car Car::operator=(Car && obj) 
{ 
    // don't need this, it will be handled by obj's destructor 
    // delete[] prBuffer; 

    using std::swap; 
    swap(prBuffer, obj.prBuffer); 
    swap(prBufferLength, obj.prBufferLength); 

    return *this; 
} 

而且看一看的Copy-and-Swap成語。它允許你使用兩種移動和複製相同的賦值運算符,但有輕微的缺點是,在不必要的複製自我的分配結果。

+0

實際上,按照你的建議推遲到對象的析構函數並不是一個好主意。如果'obj'恰好是明確從中移出的左值,則在調用後它將繼續存在。這會導致微妙的問題,例如如果'prBuffer'指向可以獨佔訪問某些資源的對象。 –

相關問題