【高質量C++/C總結2】函數內聯inline

說在開始:

作者:憨豆酒(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在實現過程中並不是絕對的,其只是對編譯器提出一個請求,編譯器有完全的權利決定該函數是否被內聯。如果此函數被內聯對性能沒有提升,那麼就不會被編譯器採納。

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