標籤:

為什麼c++ primer 5 中拷貝賦值運算符的實現不直接用條件判斷自賦值 ?

p474中的移動賦值運算符的實現中,使用了if(this != src)檢測是否自賦值。而拷貝賦值運算符的實現(p454)卻沒有這樣做。對於自賦值的處理,應該自然而然的想到通過條件判斷把,而且條件判斷更為高效。


而拷貝賦值運算符的實現(p454)卻沒有這樣做

P. 454 的代碼段第一行

// 這樣編寫賦值運算符是錯誤的!

這段代碼是說明不應該這樣做。

用 P.453 的代碼是正確的,加上自賦值判斷可能是一種優化(只是可能)。


因為拷貝有new,要考慮異常安全,即即使new拋出異常,左側指針也應置於一個有意義的狀態。而因為考慮了異常安全而適當調整了語句間的順序後,自賦值的檢測就是多餘的了。



想了很久,感覺在拷貝構造函數中也可以用 if(this != src) 來避開自賦值的情況!

在拷貝中主要考慮兩個因素,一是自賦值;二是異常安全;如果拷貝構造函數如下這麼寫,顯然都可以考慮到。原文在C++ primer(第5版),453頁。與475頁的移動賦值運算符對比。

//HasPtr是行為像值的類,有兩個數據成員:string *ps和int i;

HasPtr operator=(const HasPtr rhs){
if (this != rhs) { //if可以保障在遇到自拷貝時,不會做那麼一大堆事情,更為高效。
auto newp = new string(*rhs.ps);
delete ps; //異常安全
ps = newp;
i = ths.i;
}
return *this;
}

----------------------------------2016.10.31更新---------------------------------------------------

看了評論,發現大多數情況都不是自賦值,所以加入了額外的if判斷,會增加總體開銷。


你就這麼理解吧,move語義是把資源給偷過來。偷過來以後,原對象生命周期到了需要析構吧,但它的資源已經被偷走了,這時候析構的某些代碼就變得不合法了,所以一般move之後,原對象各成員變數都應該盡量賦值為空,對空指針之類的delete是合法的。

至於自賦值要判斷,自己偷自己,不太合理吧?偷了還要賦值為空,那偷了有何意義?

所以說這裡需要明確判斷自賦值。而對象copy,因為我只是要你的值,不是要你的資源,自己拿自己的值,合理吧!拿了,不賦值為空,也合理吧!

move語義的原理現在可以不用考慮,相信標準庫就好了!


推薦閱讀:

C++非同步回調如何更優雅?
C/C++ 適合用什麼方式去讀取批量有序的文件名?
如今C++在非底層環境下還有多少地位?
如何用C++從API開始,寫一款Windows上的視頻播放器?
學C#需要學好C++么?

TAG:C | CPrimer |