1. 程式人生 > >inline與lnk2001、lnk2019,雞肋?

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下做過簡單測試,歡迎交流。