天天看點

C++中的内聯函數

C++中的内聯函數

1. 定義

内聯函數是C++的增強特性之一,用來降低程式的運作時間。當内聯函數收到編譯器的訓示時,即可發生内聯:編譯器将使用函數的定義體來替代函數調用語句,這種替代行為發生在編譯階段而非程式運作階段

它們看起來像函數,運作起來像函數,比宏要好得多,使用時還不需要承擔函數調用的開銷。當内聯一個函數時,編譯器可以對函數體執行特定環境下的優化工作,這樣的優化對”正常“的函數調用是不可能的

下面是一個執行個體,使用内聯函數來傳回兩個數中的最大值:

#include <iostream>
 
using namespace std;
 
inline int Max(int x, int y)
{
   return (x > y)? x : y;
}
 
// 程式的主函數
int main( )
{
 
   cout << "Max (20,10): " << Max(20,10) << endl;
   cout << "Max (0,200): " << Max(0,200) << endl;
   cout << "Max (100,1010): " << Max(100,1010) << endl;
   return 0;
}
           

上面的代碼運作後結果為:

Max (20,10): 20
Max (0,200): 200
Max (100,1010): 1010
           

2. 細節

  • 内聯函數的關鍵字為inline
  • 内聯函數是一個對編譯器的建議,如果函數過于複雜,編譯器會不接受你的建議而将函數處理成普通的函數
  • 對内聯函數進行任何修改,都需要重新編譯函數的所有用戶端,因為編譯器需要重新更換一次所有的代碼,否則将會繼續使用舊的函數
  • inline關鍵字必須和函數體定義放在一起才可以實作内聯,僅僅将inline放在函數聲明之前不起任何作用。inline是一個用于實作的關鍵字而不是一個用于聲明的關鍵字

    注意:這個說法是《高品質程式設計指南C++/C語言》中的說法,在《C++Primer》中提到應在函數的聲明與定義中都加inline

    《高品質程式設計指南C++/C語言》:

    關鍵字inline 必須與函數定義體放在一起才能使函數成為内聯,僅将inline 放在函數聲明前面不起任何作用

    如下風格的函數Foo 不能成為内聯函數:

    inline void Foo(int x, int y); // inline 僅與函數聲明放在一起

    void Foo(int x, int y){}

    而如下風格的函數Foo 則成為内聯函數:

    void Foo(int x, int y);

    inline void Foo(int x, int y) // inline 與函數定義體放在一起{}

    是以說,inline 是一種“用于實作的關鍵字”,而不是一種“用于聲明的關鍵字”。一般地,使用者可以閱讀函數的聲明,但是看不到函數的定義。盡管在大多數教科書中内聯函數的聲明、定義體前面都加了inline 關鍵字,但我認為inline 不應該出現在函數的聲明中。這個細節雖然不會影響函數的功能,但是展現了高品質C++/C 程式設計風格的一個基本原則:聲明與定義不可混為一談,使用者沒有必要、也不應該知道函數是否需要内聯。

  • 在類中定義的成員函數将自動轉化為内聯函數

    注意:必須要在類内完成函數定義才會轉化成内聯函數,在類内聲明而在類外定義則不會轉化,當然隻有函數非常簡單時編譯器才會處理成内聯函數

  • 虛函數不允許内聯
  • 在調試時檢視彙編會發現内聯函數還是使用了call指令進行了函數調用而沒有用在調用處展開的方式處理,這是因為debug版本上inline是不起作用的;inline隻有在release版本下才能出現

3. 内聯函數的優缺點分析

優點:

  1. 它通過避免函數調用所帶來的開銷來提高你程式的運作速度
  2. 當函數調用發生時,它節省了變量壓棧、出棧的開銷
  3. 它避免了一個函數執行完傳回原現場的開銷
  4. 通過将函數聲明為内聯,可以把函數定義放在頭檔案内

缺點:

  1. 因為代碼的擴充,内聯函數增大了可執行程式的體積
  2. C++内聯函數的展開是編譯階段,這就意味着如果内聯函數發生了改動,那麼就需要重新編譯代碼
  3. 當把内聯函數放在頭檔案中時,它将會使頭檔案的資訊變多
  4. 有時候内聯函數并不受到青睐,比如在嵌入式系統中,嵌入式系統的存儲限制可能不允許體積很大的可執行程式

4.内聯函數和宏的差別

  1. 内聯函數在運作時可調試,而宏不可以
  2. 編譯器會對内聯函數的參數類型做安全檢查或自動類型轉換(同普通函數),而宏則不會
  3. 内聯函數可以通路類的成員變量,宏則不能
  4. 在類中定義的成員函數,自動轉化為内聯函數
  5. inline在和宏相比沒有付出任何額外代價的的情況下更安全,《Effective C++》中”Prefer consts,enums,and inlines to #defines“以及《高品質程式設計指南C++/C語言》中”用函數内聯取代宏“都建議用inline函數代替帶參宏

繼續閱讀