C++程式碼最佳化方法總結(四) (轉)

worldblog發表於2007-08-16
C++程式碼最佳化方法總結(四) (轉)[@more@]

  C++程式碼方法總結(四)
  cpp  to:cpp_bug@.com">cpp_bug@hotmail.com

五. 速度最佳化
在一些對速度要求非常苛刻的應用中,每一個週期都是要爭取的。這個部分展現了一些簡單方法來進行速度最佳化。
1. 使用類來包裹長的引數列表
一個的負擔將會隨著引數列表的增長而增加。執行時系統不得不建立堆疊來引數值;通常,當引數很多的時候,這樣一個操作就會花費很長的時間。
把引數列表包裹進一個單獨的類中並且透過引用進行傳遞,這樣將會節省很多的時間。當然,如果函式本身就很長,那麼建立堆疊的時間就可以忽略了,因此也就沒有必要這樣做。然而,對於那些時間很短而且經常被呼叫的函式來說,包裹一個長的引數列表在中並且透過引用傳遞將會提高。
2. 暫存器變數
register specifier被用來告訴一個物件將被會非常多的使用,可以把它放入暫存器中。例如:
void f()
{
  int *p = new int[3000000];
  register int *p2 = p; //store the address in a register
   for (register int j = 0; j<3000000; j++)
  {
    *p2++ = 0;
  }
  //...use  p 
  delete [] p;
}
迴圈計數是應用暫存器變數的最好的候選者。當它們沒有被存入一個暫存器中,大部分的迴圈時間都被用在了從中取出變數和給變數賦新值上。如果把它存入一個暫存器中的話,將會大大減少這種負擔。需要注意的是,register specifier僅僅是對編譯器的一個建議。就好比行內函數一樣,編譯器可以拒絕把一個物件儲存到暫存器中。另外,現代的編譯器都會透過把變數放入暫存器中來最佳化迴圈計數。Register storage specifier並不僅僅侷限在基本型別上,它能夠被應用於任何型別的物件。如果物件太大而不能裝進暫存器的話,編譯器仍然能夠把它放入一個高速儲存器中,例如cache。
用register storage specifier宣告函式型參將會是建議編譯器把實參存入暫存器中而不是堆疊中。例如:

void f(register int j, register Date d);

3. 把那些保持不變的物件宣告為const
透過把物件宣告為const,編譯器就可以利用這個宣告把這樣一個物件放入暫存器中。
4. Virtual function的執行期負擔
當呼叫一個virtual function,如果編譯器能夠解決呼叫的靜態化,將不會引入額外的負擔。另外,一個非常短的虛擬函式可以被內聯處理。在下面這個例子中,一個聰明的編譯器能夠做到靜態呼叫虛擬函式:
#include
using namespace std;
class V
{
public: 
  virtual void show() const { cout<};
class W : public V
{
public:
  void show() const { cout<};
void f(V & v, V *pV)
{
  v.show(); 
  pV->show(); 
}
void g()
{
  V v;
  f(v, &v);
}
int main()
{
  g();
  return 0;
}
如果整個出現在一個單獨的編譯單元中,編譯器能夠對main()中的g()進行內聯替換。並且在g()中f()的呼叫也能夠被內聯處理。因為傳給f()的引數的動態型別能夠在編譯期被知曉,因此編譯器能夠把對虛擬函式的呼叫靜態化。但是不能保證每個編譯器都這樣做。然而,一些編譯器確實能夠利用在編譯期獲得引數的動態型別從而使得函式的呼叫在編譯期間就確定了下來,避免了動態繫結的負擔。
5. Function s VS function pointers
用function objects取代function pointers的好處不僅僅侷限在能夠泛化和簡單的維護性上。而且編譯器能夠對function object的函式呼叫進行內聯處理,從而進一步的增強了效能
六. 最後的求助
迄今為止為大家展示的最佳化技術並沒有在設計以及程式碼的可讀性上做出妥協。事實上,它們中的一些還提高了的穩固性和可維護性。但是在一些對時間和記憶體有嚴格限制的中,上面的技術可能還不夠;有可能還需要一些會影響軟體的可移植性和擴充套件性的技術。但是這些技術只能在所有其他的最佳化技術都被應用但是還不符合要求的情況下使用。
1. 關閉RTTI和異常處理支援
當你匯入純C程式碼給C++編譯器的時候,你可能會發現有一些效能上的損失。這並不是語言或者編譯器的錯誤,而是編譯器作出的一些調整。如果你想獲得和C編譯器同樣的效能,那麼請關閉編譯器對RTTI以及異常處理的支援。為什麼會這樣呢?因為為了支援RTTI和異常處理,C++編譯器會插入額外的程式碼。這樣就增加了可執行體的大小,從而使得有所下降。當應用純C程式碼的時候,那些額外的程式碼是不需要的,所以你可以透過關閉來避免它。
2. 內聯
對時間要求苛刻的部分可以用本地彙編來重寫。結果可能是速度上的顯著提高。然而,這個方法不能想當然的就去實施,因為它將使得將來的修改非常的困難。維護程式碼的程式設計師可能對彙編並不瞭解。如果想要把軟體執行於其他平臺也需要重寫彙編程式碼部分。另外,開發和測試彙編程式碼是一件辛苦的工作,它將花費更長的時間。
3. 直接和進行互動
函式可以使你直接與作業系統進行互動。有時,直接執行一個系統命令可能會快許多。出於這個目的,你可以使用標準函式system()。例如,在一個dos/系統下,你可以這樣顯示當前目錄下的:
#include
using namespace std;
int main()
{
  system("dir");  //execute the "dir" command
}
注意:這裡是在速度和可移植性以及可擴充套件性之間做出的折衷。
 
  (全文完)


 


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

相關文章