天天看點

effective c++條款11

在 operator= 中處理自我指派

自我指派發生在對象被指派給自己時,比如w=w,但是更多的是隐性的自我指派(不能一下子看穿的)

如果i=j,那麼a[i]=a[j]算不算自我指派呢

假設有這麼一段代碼

class Bitmap {...}
class Widget
{
public:
    ...
private:
    Bitmap* pb;
}

//下面是operator=的代碼
Widget& Widget::operator=(const Widget& rhs)
{
    delete pb;
    pb=new Bitmap(*rhs.pb);
    return *this
}
           

這段operator=的代碼沒有考慮到this==&rhs

當this==&rhs時,pb早已經被釋放了,這樣new Bitmap就會因為發現異常而不會生效,其結果是this->pb指向了一個已經删除的對象

解決方法很簡單:加個證同測試

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

這個方法基本可行,但還是會存在問題,當new操作發生異常時(此時代碼就不會往下執行),pb還是會指向一個已經被删除了的對象,這說明這種方法沒有”異常安全性”

解決方法是,不考慮證同測試(證同測試會降低代碼執行速度),new之後再删除原來的指針

就像下面這樣

Widget& Widget::operator=(const Widget& rhs)
{
    Bitmap* pOrg=pb;//儲存原始的this指針
    pb=new Bitmap(*rhs.pb);//将新的對象指派給this
    delete pOrg;//删除原來的指針
    return *this
}
           

這個代碼的好處是具備”異常安全性”和”自我指派安全性”

1.當new操作發生問題時,operator=将會停止往下執行,pb會維持原來的值

2.當this==&rhs時,我們忽略它們是同一個對象的事實,建立一份rhs的副本賦給this,然後删除原始的this對象

當然還有更”騷”的操作:參數傳入時byValue,我們知道,byValue時,形參會複制實參的資料,這樣就把建立副本的工作交給了構造函數,比如下面這樣

Widget& Widget::operator=(const Widget rhs)
{
    Bitmap* pOrg=pb;//儲存原始的this指針
    pb=&rhs;//将新的對象指派給this
    delete pOrg;//删除原來的指針
    return *this;
}
           

繼續閱讀