網站首頁 編程語言 正文
前言
在C語言中,我們使用了宏函數,這是編譯器用來減少執行時間的一種優化技術。那么問題來了,在C++中,有什么更好的方法來解決這個問題呢?我們引入了內聯函數,這是編譯器用來減少執行時間的一種優化技術。我們將討論內聯函數的 “what, why, when & how”。
什么是內聯函數:
內聯函數是C++的一個增強功能,可以減少程序的執行時間。函數可以通過指示編譯器,使其成為內聯函數,這樣編譯器就可以取代那些被調用的函數定義。編譯器會在編譯時替換內聯函數的定義,而不是在運行時引用函數定義。
注意:這只是建議編譯器將函數內聯,如果函數很大(在可執行指令等方面),編譯器可以忽略 "內聯 "請求,將函數作為普通函數處理。
如何使一個函數成為內聯:
要使任何函數成為內聯函數,在其定義的開頭使用關鍵字 "inline"。
例子:
第一種情況: class A { public: inline int add(int a, int b) { return (a+b); } }; 第二種情況: class A { public: int add(int a, int b); }; inline int A::add(int a, int b) { return (a+b); } 第三種情況: inline int add_two (int a, int b) { return (a+b); }
你可以在它的類定義中定義一個成員函數,或者如果你已經在類定義中聲明了(但沒有定義)該成員函數,你可以在外面定義它。
第一種情況:
當在類成員列表中定義的成員函數默認為內聯成員函數,所以第一個class A定義里,也可以省略inline關鍵字。
一般含有幾行代碼的成員函數通常被內聯聲明,或者說可以在類的定義中定義較短的函數。
第二種情況:
如果你在類定義之外定義一個成員函數,它必須出現在包圍類定義的命名空間范圍內。你還必須使用范圍解析(::)操作符來限定成員函數的名稱。
這時如果要聲明為內聯函數,可以類中用inline關鍵字聲明它(并在其類之外定義該函數),或者在類的聲明之外用inline關鍵字定義它。
上面第二個class A是在定義處使用inline關鍵字。
第三種情況:
普通的全局函數,可以在聲明或定義處添加inline關鍵字。
在下面的例子中,成員函數Y::f()是一個內聯成員函數:
鏈接屬性:
內聯修飾符不影響成員或非成員函數的鏈接屬性:鏈接默認為外部鏈接。
內部鏈接表示只在當前文件內可訪問,外部鏈接表示多個文件可訪問。
局部類的成員函數必須在其類定義中定義。因此,局部類的成員函數是隱含的內聯函數。這些內聯成員函數沒有鏈接屬性。
為什么使用內聯:
在許多地方,我們為小的工作/功能創建函數,其中包含簡單和較少數量的可執行指令。想象一下它們每次被調用者調用時的開銷。
當遇到正常的函數調用指令時,程序會存儲緊隨函數調用語句之后的指令的內存地址,將被調用的函數加載到內存中,復制參數值,跳轉到被調用函數的內存位置,執行函數代碼,存儲函數的返回值,然后跳回執行被調用函數前剛剛保存的指令地址。運行時間開銷太大。
C++的內聯函數提供了一個替代方案。使用inline關鍵字,編譯器用函數代碼本身替換函數調用語句,然后編譯整個代碼(此過程成為代碼展開)。因此,使用內聯函數,編譯器不必跳到另一個位置來執行函數,然后再跳回來,因為被調用函數的代碼已經提供給調用程序。
通過下面的優點、缺點和性能分析,你將能夠理解為什么使用“inline”關鍵字。
優點 :
1. 它避免了函數調用的開銷,從而加快了程序執行。
2. 當函數調用發生時,它節省了在堆棧上push/pop變量的開銷。
3. 它節省了從一個函數中返回調用處的開銷。
4. 它通過利用指令緩存來更多使用本地引用。
5. 通過將其標記為內聯,你可以將函數定義放在頭文件中(也就是說,它可以包含在多個編譯單元中,而不會被鏈接器抱怨)。
缺點 :
1. 由于代碼展開,增加了最終可執行文件的大小。
2. C++的內聯是在編譯時處理的。這意味著如果你改變了內聯函數的代碼,你將需要重新編譯所有使用它的代碼,以確保它被更新。
3.??當在頭文件中使用時,它使你的頭文件變得更大,因為用戶并不關心這些信息。
4.??如上所述,它增加了可執行文件的大小,這可能會導致內存的抖動。更多的頁面故障會降低你的程序性能。
5. 有時并不實用,例如在嵌入式系統中,由于存儲空間的限制,要保證盡可能小的可執行文件。
關鍵點 :
1. 內聯函數只是一個建議,而不是強制性的。編譯器可能會也可能不會內聯你標記為內聯的函數。沒有標記為內聯的函數,在編譯或連接時,也可能被設置為內聯。
2. 內聯的工作方式就像編譯器控制的復制/粘貼,這與預處理器的宏完全不同。宏會被強行內聯,會污染所有的命名空間和代碼,不容易調試。
3. 所有在類中聲明并定義的成員函數默認是內聯的。所以不需要明確定義為內聯。
4. 虛函數不支持內聯。但是,有時候,當編譯器可以確定對象的類型時(即對象是在同一個函數體中聲明和構造的),即使是一個虛擬函數也會被內聯,因為編譯器確切地知道對象的類型。
5. 模板方法/函數并不總是被內聯的(它們在頭文件中的存在不會使它們自動內聯)。
6. 大多數編譯器會對遞歸函數進行內聯,有些編譯器有此功能的開關,并可以設置最大的遞歸深度。
總結
原文鏈接:https://blog.csdn.net/guoqx/article/details/122045450
相關推薦
- 2022-08-18 python數據可視化pygal模擬擲骰子實現示例_python
- 2022-04-06 一篇文章帶你了解C/C++的回調函數_C 語言
- 2022-11-22 GoLang?channel關閉狀態相關操作詳解_Golang
- 2022-05-15 C++11:lambda表達式詳細介紹
- 2022-08-16 python中的屬性管理機制詳解_python
- 2022-05-29 python3中的類繼承你真的了解嗎_python
- 2022-03-09 SQL數據庫語句大全_數據庫其它
- 2022-05-01 WinForm中Application.Idle方法詳解_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支