C++程式設計最佳實踐(轉)

heying1229發表於2007-07-28
隨著計算機語言的發展,我們現在編寫一個程式越來越容易了。利用一些軟體開發工具,往往只要透過滑鼠的拖拖點點,計算機就會自動幫你生成許多程式碼。但在很多時候,計算機的這種能力被濫用了,我們往往只考慮把這個程式搭起來,而不去考慮程式的效能如何,程式是否足夠的健壯。而此節課的目的主要是介紹一些編碼的經驗,讓大家編寫的程式更加健壯和高效能。

  1、Prefer const and inline to #define

  在C++程式設計中應該儘量使用const和inline來代替#define,儘量做到能不用#define就不用。#define常見的用途有“定義常量”以及“定義宏”,但其中存在諸多的弊病。

  第一,查錯不直觀,不利於除錯。Define的定義是由預處理程式處理的,作的是完全的文字替換,不做任何的型別檢查。在編譯器處理階段,define定義的東西已經被完全替換了,這樣在debug的時候就看不到任何的相關資訊,即跟蹤時不能step into宏。例如,把ASPECT_RATIO用define定義成1.653,編譯器就看不到ASPECT_RATIO這個名字了。如果編譯器報1.653錯,那麼就無從知道此1.653來自於何處。在真正編碼的時候應該使用如下的語句來定義:

static const double ASPECT_RATIO = 1.653;

  第二,沒有任何型別資訊,不是type safe。因為它是文字級別的替換,這樣不利於程式的維護。

  第三,define的使用很容易造成汙染。比如,如果有兩個標頭檔案都定義了ASPECT_RATIO, 而一個CPP檔案又同時包含了這兩個標頭檔案,那麼就會造成衝突。更難查的是另外一種錯誤,比如有如下的程式碼:

  // in header file def.h
  #define Apple 1
  #define Orange 2
    #define Pineapple 3
   …
  // in some cpp file that includes the def.h
  enum Colors {White, Black, Purple, Orange};

  在.h檔案中Orange被定義成水果的一種,而在.cpp檔案中Orange又成為了一種顏色,那麼編譯器就會把此處的Orange替換成2,編譯可能仍然可以透過,程式也能夠執行,但是這就成了一個bug,表現出古怪的錯誤,且很難查錯。再比如定義了一個求a與b哪個數大的宏,#define max(a,b) ((a) > (b) ? (a) : (b))

  int a = 5, b = 0;
  max(++ a, b);
  max(++ a, b + 10);

  在上面的操作中,max(++ a, b); 語句中a被++了兩次,而max(++ a, b + 10); 語句中a只加了一次,這樣在程式處理中就很有可能成為一個bug,且此bug也非常的難找。在實際編碼時可以使用如下的語句來做:

  template
  inline const T&
  max(const T& a, const T& b) { return a > b ? a : b; }

  2、Prefer C++-style casts

  在程式中經常會需要把一種型別轉換成另外一種型別,在C++中應該使用static_cast、const_cast、dynamic_cast、reinterpret_cast關鍵字來做型別轉換。因為這有以下好處,一是其本身就是一種註釋,在程式碼中看到上面這些關鍵字就可馬上知道此處是進行型別轉換。二是C語言中型別轉換通常是很難進行搜尋的,而透過關鍵字cast則可以很容易的找到程式中出現型別轉換的地方了。

  3、Distinguish between prefix and postfix forms of increment and decrement operators

  通常對於作業系統或編譯器自身支援的型別,prefix(字首,如++i)與postfix(字尾,如i++)的效果是一樣的。因為現在的編譯器都很聰明,它會自動做最佳化,這兩者的彙編程式碼是一樣的,效能不會有差別。但有時候也會有不同的,如一些過載了運算子的型別。下面是模擬prefix與postfix的操作過程,可以發現在postfix操作中會生成一個臨時變數,而這一臨時變數是會佔用額外的時間和開銷的。

  // prefix form: increment and fetch
  UPInt& UPInt::operator++()
   {
    *this += 1; // increment
   return *this; // fetch
   }
  // postfix form: fetch and increment
   const UPInt UPInt::operator++(int)
   {
    UPInt oldValue = *this; // fetch
   ++(*this); // increment
    return oldValue; // return what was fetched
   }


  一般情況下不需要區分是先++,還是後++,但是我們在編寫程式的時候最好能習慣性的將其寫成++i的形式,如在使用STL中的iterator時,prefix與postfix會有相當大的效能差異。請不要小看這些細節,實際在編寫程式的時候,若不注意具體細節,你會發現程式的效能會非常的低。但要注意,雖然在大多數情況下可以用prefix來代替postfix,但有一種情況例外,那就是有[]運算子時,比如gzArray [++index] 是不等於 gzArray[index++]的。

[@more@]

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

相關文章