C++ inline用法以及與宏的區別

函數內聯的工作過程:

對於任何內聯函數,編譯器在符號表裏放入函數的聲明(包括名字、參數類型、返回值類型)。 如果編譯器沒有發現內聯函數存在錯誤,那麼該函數的代碼也被放入符號表裏。 在調用一個內聯函數時,編譯器首先檢查調用是否正確 (進行類型安全檢查,或者進行自動類型轉換,當然對所有的函數都一樣)。 如果正確,內聯函數的代碼就會直接替換函數調用,於是省去了函數調用的開銷

一、inline用法

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

如下風格的函數Fun 不能成爲內聯函數:

inline void Fun(int x, int y); // inline 僅與函數聲明放在一起
void Fun(int x, int y)
{
}
而如下風格的函數Fun則成爲內聯函數:
void Fun(int x, int y);
inline void Fun(int x, int y) // inline 與函數定義體放在一起
{
}

可以這麼理解,inline 是一種“用於實現的關鍵字”,而不是一種“用於聲明的關鍵字”。

2. 一般地,用戶可以閱讀函數的聲明,但是看不到函數的定義。用戶沒有必要,也不應該知道函數是否需要內聯。

3. 定義在類聲明之中的成員函數將自動地成爲內聯函數,例如

class A
{
public:
void Fun(int x, int y) {  } // 自動地成爲內聯函數
}
將成員函數的定義體放在類聲明之中雖然能帶來書寫上的方便,但不是一種良好的編程
風格,上例應該改成:

// 頭文件
class A
{
public:
void Fun(int x, int y);
}
// 定義文件
inline void A::Fun(int x, int y)
{

}


二、inline優點和缺點

1. 優點:

1)inline定義的內聯函數,函數代碼被放入符號表中,在使用時進行替換(像宏一樣展開),效率很高。

2)類的內聯函數也是函數。編繹器在調用一個內聯函數,首先會檢查參數問題,保證調用正確,像對待真正函數一樣,消除了隱患及侷限性。

3)inline可以作爲類的成員函數,並可以使用所在類的保護成員及私有成員。

2.缺點:

內聯是以代碼膨脹(複製)爲代價,僅僅省去了函數調用的開銷,從而提高函數的執行效率。如果執行函數體內代碼的時間,相比於函數調用的開銷較大,那麼效率的收獲會很少。另一方面,每一處內聯函數的調用都要複製代碼,將使程序的總代碼量增大,消耗更多的內存空間。

以下情況不宜使用內聯:
(1)如果函數體內的代碼比較長,使用內聯將導致內存消耗代價較高。

(2)如果函數體內出現循環,那麼執行函數體內代碼的時間要比函數調用的開銷大

三、define宏的優點和缺點

1.優點:

1. 提高了程序的可讀性,同時也方便進行修改;  

2. 提高程序的運行效率:使用帶參的宏定義既可完成函數調用的功能,又能避免函數的出棧與入棧操作,減少系統開銷,提高運行效率; 

3.宏是由預處理器處理的,通過字符串操作可以完成很多編譯器無法實現的功能。比如##連接符。

2.缺點:

1. 由於是直接嵌入的,所以代碼可能相對多一點;  

2. 嵌套定義過多可能會影響程序的可讀性,而且很容易出錯;  

3. 對帶參的宏而言,由於是直接替換,並不會檢查參數是否合法,存在安全隱患。

C++ 語言的函數內聯機制既具備宏代碼的效率,又增加了安全性,而且可以自由操作類的數據成員。 
所以在C++ 程序中,應該用內聯函數取代所有宏代碼,"斷言assert"恐怕是唯一的例外。 

assert是僅在Debug版本起作用的宏,它用於檢查"不應該"發生的情況。 
爲了不在程序的Debug版本和Release版本引起差別,assert不應該產生任何副作用。 
如果assert是函數,由於函數調用會引起內存、代碼的變動,那麼將導致Debug版本與Release版本存在差異。 
所以assert不是函數,而是宏。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章