說在開始:
作者:憨豆酒(YinDou),聯繫我[email protected],熟悉圖形學,圖像處理領域,本章的源代碼可在此倉庫中找到: https://github.com/douysu/person-summary 如果大家發現錯誤以及不合理之處,還希望多多指出。
我提煉了《C++ Primer》、《侯捷C++》、《高質量程序設計指南——C/C++語言》等資料中的重要部分,並總結成此博文。其中涉及到許多我個人對C++的理解,如若有不合理之處,還請朋友們多多指出,我會虛心接受每一個建議。
內聯函數inline
內聯函數的實際目的是爲了提高函數的執行效率,在條件允許的情況下,編譯器會自動將內聯函數中的代碼直接替換函數調用語句,可以幫助減少函數調用開銷:參數壓棧、跳轉、退棧、返回值等,提高了代碼的執行速度。
此案例說明了這個問題。
int sumFunc(int x,int y);
inline int sumFunc(int x,int y)
{
return (x+y);
}
int main()
{
int sumV=sumFunc(2,3);
return 0;
}
//被擴展成代碼
int main()
{
int sumV = 2+3;
return 0;
}
內聯函數inline的使用頻率
爲了查看inline在實際開發中的使用頻率,我查閱了一些C++開源項目,發現inline的使用頻率是非常高的,例如C++ STL algorithm中的max函數的源碼,可以非常清楚的看到設計algorithm的人使用了inline。
ntemplate<typename _Tp>
_GLIBCXX14_CONSTEXPR
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
__glibcxx_function_requires(_LessThanComparableConcept<_Tp>)
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
使用內聯函數inline的注意事項
()內聯函數的代碼不應過長。內聯函數是以代碼拷貝爲代價的,僅僅省去的函數調用的開銷。試想,如果你的方法中的代碼執行時間比函數調用過程花費的時間還長,那就沒有必要在使用內聯函數了。當然,函數體內出現多次循環或者其他複雜的結構:遞歸、排序、遍歷等等,那內聯函數意義也是微乎其微的。例如,這樣的方法。
void funC(){
for(int i=0;i<=20;i++)
for(......)
for(......)
}
(2)計算函數(代碼長度較短)更加適合內聯。例如計算圓的面積,圓的半徑,min,max,sum,average等等,當在項目封裝庫的過程中,記得使用內聯。當然C++設計師也是這樣做的,例如min,max。
(3)inline必須與函數定義放在一起纔會起作用。在C++中,有一非常重要的理念,函數的聲明和定義是兩大部分。通常函數的聲明會放在頭文件.h中,而函數的定義會放在可編譯單元.cpp中。 在使用其他人寫好的類時,只需要include相應的頭文件,使用者無需關心該函數是否爲內聯函數,例如使用algorithm中的min函數一樣,我們無需知道此函數是否爲內聯函數。
(4)在哪個cpp中定義內聯,就只能在該cpp中使用。例如
//InlineSample.h
#ifndef NEILIANSAMPLE_H
#define NEILIANSAMPLE_H
class InlineSample
{
public:
InlineSample();
void setValue(float inValue);
float value;
};
#endif
//InlineSample.cpp
#include "InlineSample.h"
InlineSample::InlineSample() {
}
inline void InlineSample::setValue(float inValue) {
value = inValue;
}
//main.cpp
#include "InlineSample.h"
#include<iostream>
using namespace std;
int main() {
InlineSample ns;
ns.setValue(2.0f);
printf("當前的值%f", ns.value);
cin.get();
}
此種情況會編譯錯誤,因爲在InlineSample.cpp中定義的inline,卻想要在main.cpp中使用,顯然是錯誤的。這也是我自己在開發中遇到的問題,需要注意。此時應將setValue方法的定義放到.h文件中,即可完成這種需求。
//InlineSample.h
#ifndef NEILIANSAMPLE_H
#define NEILIANSAMPLE_H
class InlineSample
{
public:
InlineSample();
void setValue(float inValue);
float value;
};
inline void InlineSample::setValue(float inValue) {
value = inValue;
}
#endif
這種方式的實現原理:當include頭文件InlineSample.h時,就將inline的定義代碼拷貝到了相應的cpp,這樣當然不會出現問題了,但是這與(3)中的說法好像有點相違背,看大家怎麼選擇了。
(5)inline在實現過程中並不是絕對的,其只是對編譯器提出一個請求,編譯器有完全的權利決定該函數是否被內聯。如果此函數被內聯對性能沒有提升,那麼就不會被編譯器採納。