Thinking again in C++(二)自賦值是非公斷 (轉)

gugu99發表於2007-11-15
Thinking again in C++(二)自賦值是非公斷 (轉)[@more@]

  愛死Thinking in系列了,所以起了這個名字。本文的思想也部分來至於這套書,或參照對比,或深入挖掘,或補益拾慧,或有感而發,既包括Thinking in C++,甚至也包括Thinking in 。

  Thinking again in C++(二)自賦值是非公斷

  關鍵字:C++,自賦值,自複製,賦值,assign,assignment,複製,複製,copy

  1.需要考慮的自賦值。當類包含指標或引用成員時應注意檢查。
  class String
  {
  private:
  char * pc_Buffer;
  public:
  String & operator=(const String & strR);
  String & operator+=(const String & strR);
  //...
  };
  (1)類內部:對稱賦值運算子、接受自身型別或自身基類型別引數的成員,有時候還要考慮+=系列運算子。
  String & String::operator=(const String & strR)
  {
  if (this==&strR)  1]
  return *this;
  delete [] pc_Buffer;  2]
  pc_Buffer=new char[strlen(strR.pc_Buffer)+1];//[3]
  //...
  }
  [1]中的判斷是必須的。如果this==&strR,[2]將本身刪除,[3]就會使用“懸掛指標”。
  下面operator+=()的實現隱藏著錯誤。
  String & String::operator+=(const String & strR)
  {
  int iLengthNew=strlen(pc_Buffer)+strlen(strR.pc_Buffer);
  char * pcBufferNew=new char[iLengthNew+1];
  strcpy(pcBufferNew,pc_Buffer);
  delete [] pc_Buffer;  4]
  strcat(pcBufferNew,strR.pc_Buffer);  5]
  pc_Buffer=pcBufferNew;
  return *this;
  }
  如果this==&strR,[4]將本身刪除,[5]就會使用“懸掛指標”。正確的做法不必使用判斷語句,只需調換[4][5]兩條語句的順序。
  (2)類外部(包括友元):接受多個同一型別引數或多個有繼承關係的型別引數的函式。
  class CDerive : public CBase{};
  void f(CBase & b1,CBase & b2);
  void g(CBase & b,CDerive & d);
  CBase bSame;
  CDerive dSame;
  f(bSame,bSame);  1]
  f(dSame,dSame);  2]
  g(dSame,dSame);  3]
  [1][2][3]都出現了自賦值,所以f()、g()的設計中都要有所考慮。

  2.不可能出現自賦值。
  (1)複製構造器:因為正在構造的還未完全生成,而傳遞給構造器的實參物件是已構造完畢的物件,這兩者絕不可能是同一物件。
  (2)非對稱賦值運算子:即使形參型別是自身的基類。若D是B的派生類,無論是否過載了對稱賦值運算子,D類物件之間的賦值行為都不會D::operator=(const B & b)。
  class CDerive : public CBase
  {
  public:
  operator=(const CBase & b);  用考慮this和b之間的自賦值
  void f(const CBase & b);  要考慮this和b之間的自賦值
  };
  CDerive dSame;
  dSame=dSame;  1]
  dSame.f(dSame);  2]
  語句[1]中,不會把dSame上溯造型為CBase,而是呼叫預設或自定義的D::operator=(const D & d)。只有等式左邊確為D,右邊確為B,才呼叫D::operator=(const B & b),這時不可能出現自賦值。相反,語句[2]中,編譯器會把dSame上溯造型為CBase,所以f()需要考慮自賦值。

  3.不是自賦值的賦值。僅僅內容相同的賦值不是自賦值。
  CTest a,b,same;
  a=same;
  b=same;
  a=b;  1]
  [1]不是自賦值,不會出問題,不需要檢查,而且內容相同無法直接用地址來檢查。

  4.不應該檢查的自賦值。
  strcpy(char * strDest,const char * strSrc);中,當strDest==strSrc時,是自賦值,但並不會出錯。
  發現自賦值直接返回,這種特定情況下,也許能提高函式10倍,但絕大多數沒有出現自賦值時都多了一個條件判斷,可能降低函式效率10%,最後綜合計算加權平均效率可能還是降低了。這取決於自賦值出現的機率。
  設不判斷自賦值,函式時間為1;若檢查自賦值,設出現自賦值的機率為x,直接返回函式執行時間為0.1,不出現自賦值,多了一個條件判斷函式執行時間為1.1,那麼如果要求加權平均效率不降低:
  0.1x+1.1(1-x)<1
  解之,得:x>0.1。也就是說自賦值出現的機率必須大於10%,這在實際程式碼中可能嗎?


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-982478/,如需轉載,請註明出處,否則將追究法律責任。

相關文章