C++中在operator=中處理“自我賦值”(11)---《Effective C++》__C++

來源:互聯網
上載者:User
條款11:在**重點內容**operator=中處理“自我賦值”

“自我賦值”發生在對象被賦值給自己時:
class Widget{…}
Widget w;

w=w;//賦值給自己
a[i]=a[j];//潛在的自我賦值,如果i和j有相同的值,這便是個自我賦值
*px=*py;//潛在的自我賦值,如果px和py指向同一個問題,這也是自我賦值
甚至如下這樣也可以:
class Base {…};
class Derived:public Base {…};
void doSomething(const Base& rb,Derived* pd);//rb和pd可能其實是同一個對象

很多情況下“自我賦值”是安全的,不需要額外操心,然而如果你嘗試自行管理資源(如果你打算寫一個用於資源管理的class就這樣做),可能會掉進“在停止使用資源之前以外釋放了它”的陷阱,如:

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

這裡的自我賦值問題是,operator=函數內部*this和rhs有可能是同一個對象,如果這樣的話,delete pb銷毀的不只是當前對象那個的bitmap,同時rhs的bitmap也被銷毀掉了,那麼在自我賦值的時候程式會發現rhs.pb指標指向的是一個已經被刪除的對象。

如何來阻止這種錯誤呢,具體有多種方法:
1)傳統做法是operator=最前面加一個“證同測試”達到“自我賦值”的校正目的,具體見如下代碼:

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

這樣的代碼有沒有什麼錯誤呢。可以看到,具備了“自我賦值安全性”,那還有什麼問題呢。答案就是“異常安全性”,這種解決方案對於異常並沒有什麼很好的作用,具體來說,如果new Bitmap(*rhs.pb)出現異常的話(不論是因為分配時記憶體不足或者Bitmap的copy建構函式拋出異常),pb最終指向一個被刪除的Bitmap,這樣的指標會出現null 指標異常等乙烯類問題。
2)這種方法主要側重於“異常安全性”方面,我們只需注意在賦值pb所指的東西之前別刪除pb:

Widget& Widget::operator=(const Widget& rhs){    Bitmap* pOrig=pb;    pb=new Bitmap(*rhs.pb);    delete pOrig;//刪除原先的pb    return *thsis;}

這樣的話,如果“new Bitmap”拋出異常,pb保持原狀,即使沒有“證同測試”,這段代碼還是可以處理自我賦值,因為我們對原bitmap做了一份複件、刪除原bitmap、然後指向新製造的那個複件。PS:如果此時需要考慮效率的話,需要先估計“自我賦值”發生的頻率有多高。如果高的話,我們就將“證同測試”加在函數起始處。如果“證同測試”發生頻率不高的話,推薦不要添加“證同測試”,因為添加這項測試也需要耗費成本,降低程式執行效率。

3)如果對上述兩種方法還是不太滿意的話,還有一個替代方案,不僅“異常安全”同時“自我賦值安全”,即使用copy and swap技術實現,參看以下代碼:

class Widget{    ...    void swap(Widget& rhs);    ...};Widget& Widget::operator=(const Widget& rhs){    Widget temp(rhs);//使用copy建構函式,為rhs資料製作一份副本    swap(temp); //將*this資料和上述所述複件的資料交換    return *this;}   

怎樣,這種方法不錯吧。但是代碼看起來邏輯並沒有多麼清晰,這也是這種方法的缺點吧。

總結:
1)確保當前對象自我複製時operator=有良好的行為,其中包括“來來源物件”和“目標對象”的地址、精心周到的語句順序以及copy-and-swap操作;
2)確定任何函數如果操作一個以上的對象,而其中多個對象是同一個對象那個時候,其行為依然正確。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.