程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Effective C++(11) 自我賦值(a=a)時會發生什麼?

Effective C++(11) 自我賦值(a=a)時會發生什麼?

編輯:C++入門知識

問題聚焦:

自我賦值看似有點愚蠢的行為,其實總會發生的 首先:它是合法的, 其次,它不一定是安全的, 再次,它有時候不是那麼明顯。
先看一個Demo
class Widget { ... };
Widget w;
...
 /** 最明顯的自我賦值 **/
w = w;   

/** 不那麼明顯的自我賦值 **/
// 在某個地方實現了i = j或者相同作用的事情
a[i] = a[j]

/** 潛在的自我賦值 **/
*px = *py;

/** 更為隱蔽的自我賦值“別名” **/
class Base { ... };
class Derived : public Base { ... };
void doSomething( const Base& rb, Derived* pd);     // rb 和 *pd可能是同一對象


一般而言,如果某段代碼操作指針和音樂能夠,而它們被用來指向多個相同類型的對象,就需要考慮這些對象是否為同一個了。
自我賦值可能帶來的兩種潛在的危險: 自我賦值安全性異常安全 來看下面的例子:
class Bitmap { ... };
class Widget {
    ... 
private:
    Bitmap* pd;
};

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

自我賦值安全性:
若rhs和當前對象是同一對象,那麼在銷毀當前對象的pb時,把rhs的對象也銷毀了。

改進:認同測試

/** operator=的代碼實現 **/
Widget&
Widget::operator=(const Widget& rhs)
{
    if (this == &rhs) return *this;   // 認同測試

    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}


上述改進後的代碼避免了自我賦值安全性問題。 我們來關注一下第二個問題 異常安全性:
如果new Bitmap()發生異常,那麼結果就是pb賦值直白,Widget最終持有一個指針指向一塊被刪除的Bitmap。
改進一:盡心安排語句

/** operator=的代碼實現 **/
Widget&
Widget::operator=(const Widget& rhs)
{
    Bitmap* pOrig  = pb;
    pb = new Bitmap(*rhs.pb);     // 如果new Bitmap拋出異常,pb保持原狀
    delete pOrig;
    return *this;
}


改進方案二:copy and swap

class Widget {
...
void swap(Widget& rhs);
...
};

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

思想:
拷貝構造函數要聲明為“按值傳遞” 按值傳遞會造成一份副本


小結:
確保當對象自我賦值時operator=有良好的行為。
包括:
對象來源
目標對象地址
語句順序
確定任何函數如果操作一個以上的對象,而其中多個對象是同一個對象時,其行為仍然正確。



參考資料: 《Effective C++ 3rd》

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved