2015-09-01 56 views
6

想象一下,一個項目中,有一個像一個接口類以下內容:vtable爲什麼不能包含重複的函數?

struct Interface 
{ 
    virtual void f()=0; 
    virtual void g()=0; 
    virtual void h()=0; 
}; 

假設其他地方,有人希望創建一個類實現這個接口,爲此fgh都做同樣的事情。

struct S : Interface 
{ 
    virtual void f() {} 
    virtual void g() {f();} 
    virtual void h() {f();} 
}; 

那麼這將是一個有效的優化,以產生一個虛函數表爲S其條目都指向S::f,從而節省的包裝功能gh通話。

打印虛函數表的內容,但表示不執行這種優化:

S s; 
void **vtable = *(void***)(&s); /* I'm sorry. */ 
for (int i = 0; i < 3; i++) 
    std::cout << vtable[i] << '\n'; 

0x400940
0x400950
0x400970

-O3-Os沒有編譯效果,就像在clang和gcc之間切換一樣。

爲什麼這個優化機會錯過了?

目前,這些是我已經考慮(並拒絕)的猜測:

  1. V表打印代碼實際打印垃圾。
  2. 性能改進被認爲是毫無價值的。
  3. ABI禁止它。因爲...

    // somewhere-in-another-galaxy.hpp 
    struct X : S { 
        virtual void f(); 
    }; 
    
    // somewhere-in-another-galaxy.cpp 
    include <iostream> 
    void X::f() { 
        std::cout << "Hi from a galaxy far, far away! "; 
    } 
    

    如果編譯器可以實現您的優化這段代碼是行不通的

+8

這個優化對於符合代碼是可見的,因爲指向成員函數的指針會比較相等。 –

+0

這看起來很幼稚,但對我來說,調用'f' *的函數本身不是'f'。所以這很奇怪,如果指向成員函數是平等的,你不覺得嗎? –

+2

@David Schwartz:llvm被認爲能夠完成像通過函數指針的內聯代碼。想必它也可以在'g'和'h'中嵌入'f'的主體呢?這與OP提出的優化不一樣我猜...這個優化在實踐中並不是很重要,所以沒有人在意?感覺就像編譯器檢測到的「指向成員函數的指針」一樣,或者可以修改標準以允許以允許複製ellision的相同方式進行優化 –

回答

2

這種優化是無效的。

Interface* object = new X; 
object->g(); 

我的翻譯單元的編譯器不知道你的類內部實現,從而爲克()和h(),它只是把我的類的虛函數表引用到相應的條目類VFT 。

+0

問題不在於「您的編譯器不知道我的類內部實現」 - 即使「 g()'在頭文件中實現,這是「其他編譯器不需要繼續使我的編譯器的優化有效」(它可以通過覆蓋'f'覆蓋'g'來實現)。 – PBS

+1

另一個注意事項:當在匿名命名空間中定義'S'並打開'-O2'時,gcc *會合並所有的vtable條目(從而爲此答案提供可信度)。 – PBS

相關問題