C++ 函數內聯

來源:互聯網
上載者:User
1. 用內聯取代宏代碼


C++ 語言支援函數內聯,其目的是為了提高函數的執行效率(速度)。

在 C 程式中,可以用宏代碼提高執行效率。宏代碼本身不是函數,但使用起來象函 數。 前置處理器用複製宏代碼的方式代替函數調用, 省去了參數壓棧、 產生組合語言的 CALL 調用、返回參數、執行 return 等過程,從而提高了速度。使用宏代碼最大的缺點是容 易出錯 ,前置處理器在複製宏代碼時常常產生意想不到的邊際效應。


例如

#define MAX(a, b)         (a) > (b) ? (a) : (b)

語句

result = MAX(i, j) + 2 ;

將被前置處理器解釋為

result = (i) > (j) ? (i) : (j) + 2 ;

由於運算子‘ +’比運算子‘ :’的優先順序高,所以上述語句並不等價於期望的

result = ( (i) > (j) ? (i) : (j) ) + 2 ;

如果把宏代碼改寫為

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )

則可以解決由優先順序引起的錯誤。但是即使使用修改後的宏代碼也不是萬無一失的,例 如語句

result = MAX(i++, j);

將被前置處理器解釋為

result = (i++) > (j) ? (i++) : (j);

對於 C++ 而言,使用宏代碼還有另一種缺點:無法操作類的私人資料成員 ,也就是說宏代碼基本是針對公用或全域操作的。


讓我們看看 C++ 的“函數內聯”是如何工作的。對於任何內嵌函式,編譯器在符號 表裡放入函數的聲明(包括名字、參數類型、傳回值類型) 。如果編譯器沒有發現內聯 函數存在錯誤,那麼該函數的代碼也被放入符號表裡。在調用一個內嵌函式時,編譯器 首先檢查調用是否正確(進行型別安全檢查,或者進行自動類型轉換,當然對所有的函 數都一樣) 。如果正確,內嵌函式的代碼就會直接替換函數調用,於是省去了函數調用 的開銷。這個過程與預先處理有顯著的不同,因為前置處理器不能進行型別安全檢查 ,或者 進行自動類型轉換。假如內嵌函式是成員函數,對象的地址( this)會被放在合適的地 方,這也是前置處理器辦不到的。


C++ 語言的函數內聯機制既具備宏代碼的效率,又增加了安全性,而且可以自由操 作類的資料成員。所以在 C++ 程式中,應該用內嵌函式取代所有宏代碼, “斷言 assert” 恐怕是唯一的例外。 assert 是僅在 Debug 版本起作用的宏,它用於檢查“不應該”發生 的情況。為了不在程式的 Debug 版本和 Release 版本引起差別, assert 不應該產生任何 副作用。 如果 assert 是函數, 由於函數調用會引起記憶體、 代碼的變動, 那麼將導致 Debug 版本與 Release 版本存在差異。 所以 assert 不是函數, 而是宏。


2. 內嵌函式的編程風格


關鍵字 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 程式設計風格 的一個基本原則:聲明與定義不可混為一談,使用者沒有必要、也不應該知道函數是否需 要內聯。


定義在類聲明之中的成員函數將自動地成為內嵌函式,例如

class A  {  public:      void Foo(int x, int y) { … }   // 自動地成為內嵌函式  }


將成員函數的定義體放在類聲明之中雖然能帶來書寫上的方便,但不是一種良好的編程 風格,上例應該改成:

// 標頭檔  class A  {  public:      void Foo(int x, int y);  }  // 定義檔案  inline void A::Foo(int x, int y)  {  …  }

3. 慎用內聯


內聯能提高函數的執行效率,為什麼不把所有的函數都定義成內嵌函式?


如果所有的函數都是內嵌函式,還用得著“內聯”這個關鍵字嗎?


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


消耗更多的記憶體空間。以下情況不宜使用內聯:


( 1)如果函數體內的代碼比較長,使用內聯將導致記憶體消耗代價較高。


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


類的建構函式和解構函式容易讓人誤解成使用內聯更有效。要當心建構函式和析構 函數可能會隱藏一些行為,如“偷偷地”執行了基類或成員對象的建構函式和解構函式。 所以不要隨便地將建構函式和解構函式的定義體放在類聲明中 。

以上就是C++ 函數內聯的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.