inline與lnk2001、lnk2019,雞肋?
inline函式居然出現了lnk2001、lnk2019,先貼程式碼。
a.h
#pragma once
class A
{
public:
inline void foo();
void use_foo();
};
a.cpp
#include "A.h"
inline void A::foo()
{
}
void A::use_foo()
{
foo();//此行註釋掉會產生lnk2019錯誤
}
main.cpp
#include "A.h"
int main()
{
A a;
a.foo();
return 0;
}
看似簡單的程式,揭示出inline的使用限制:
1、在標頭檔案中,類成員函式宣告為inline時實現函式體,比如:
#pragma once
class A
{
public:
inline void foo(){};//實現了函式體即便是空的
void use_foo();
};
2、在標頭檔案和原始檔中分開實現,此類原始檔中的“任意非inline函式續”需呼叫過此函式,然後其他原始檔中才可用,此時連結時不會出現lnk2001 lnk2019錯誤。
如:上面的a.cpp
兩種方法:
第一種缺點是破壞封裝,生成的庫拿給別人用總不希望被看到函式體的實現吧
第二種封裝性好,別人只能看到宣告,缺點是容易產生lnk錯誤。
其實編譯器儘量把標頭檔案中的帶實現的函式優化為inline,只要不帶迴圈之類的就可以不用宣告inline。
inline只有在達到一定呼叫頻率量級上才會顯得快。比如:Release編譯 /O2開啟,第一種10億次迴圈呼叫的差距大概在幾十毫秒。第二種反而比非inline慢幾到十幾毫秒。
結論:inline沒必要使用
如果是在標頭檔案中實現類函式體,inline關鍵字不必使用,因為編譯器預設會將標頭檔案實現的類函式儘量優化為inline,而且這種破壞封裝性,如果是編譯給別人用的庫還是算了。
如果是在原始檔中實現類函式體,inline關鍵字不能用,因為你不能保證該原始檔一定需要呼叫該函式,可能造成其它原始檔的lnk2001 lnk2019連結錯誤。
如果追求極致效能又怕編譯器不靠譜,請在標頭檔案中宣告inline且同時實現函式體,即便如此,編譯器也會考量是否可編譯為inline函式,並且前提是優化選項開啟,比如VS的 /O2、g++的 -O2
本人僅在vs2012 release下做過簡單測試,歡迎交流。