1. 程式人生 > >Effective c++ 條款11:在operator=中處理“自我賦值”

Effective c++ 條款11:在operator=中處理“自我賦值”

自我賦值發生在物件被賦值給自己時,且有些時候自我賦值不是這麼容易能被看出來,比如
a[i] = a[j]; //存在自我賦值的可能性(i==j時 )
*px = *py; //存在自我賦值的可能性(px和py指向同一物件)
這些自我賦值是別名帶來的結果,所謂別名就是有一個以上的方法指稱某物件。如果某段程式碼用來操作指向多個相同型別物件的pointers或references,就要考慮自我賦值的可能性。
實際上兩個物件如果來自同一個繼承體系,它們甚至不需宣告為相同型別就可能造成別名。

證同測試(identity test)

Widget& Widget::opearator=(const
Widget& rhs) { if (&rhs == this) return *this; delete pb; pb = new Bitmap(rhs.pb); return *this; }

然而這一版本並不具備異常安全性,當因分配時記憶體不足等問題導致異常時,pb將指向一塊被刪除的Bitmap。

注意在複製所指內容之前別刪除

Widget& Widget::opearator=(const Widget& rhs) {
    Bitmap* pOrig = pb;
    pb = new Bitmap(rhs.pb);
    delete
pOrig; return *this; }

現在,如果new操作丟擲異常,pb將保持現狀,且即使沒有證同測試,這段程式碼也能處理自我賦值。
如果想要在這段程式碼前加入證同測試,需要考慮自我賦值發生的概率,畢竟比較也是需要時間的。

copy and swap

Widget& Widget::opearator=(const Widget& rhs) {
    Widget temp(rhs);
    swap(temp);
    return *this;
}

另一種類似的方法是:

Widget& Widget::opearator=(Widget rhs) {//注意是值傳參
swap(rhs); return *this; }

這種方法犧牲了清晰性,然而將copying動作從函式本體內移至函式引數構造階段,令編譯器有時生成更高效的程式碼。