2010-02-25 13 views
0

我想知道是否存在一種可能的優化,即編譯器不需要將vptr分配給實例化對象,即使對象的類型是具有虛擬方法的類。是否有類聲明虛方法並且編譯器不需要使用vptr的情況?

例如考慮:

#include <iostream> 
struct FooBase 
{ 
    virtual void bar()=0; 
}; 

struct FooDerived : public FooBase 
{ 
    virtual void bar() { std::cout << "FooDerived::bar()\n"; } 
}; 

int main() 
{ 
    FooBase* pFoo = new FooDerived(); 
    pFoo->bar(); 

    return 0; 
} 

在這個例子中,編譯器肯定知道會是怎樣的PFOO在編譯時的類型,所以它並不需要使用的vptr爲PFOO,對不對? 有沒有更有趣的情況下,編譯器可以避免使用vptr?

回答

4

大廈Andrew Stein's answer,因爲我想你也想知道什麼時候可以避免所謂的「虛擬功能的運行時間開銷」。 (開銷是存在的,但它是微小,很少值得擔憂的。)

這真的很難避免虛表指針的空間,但指針本身可以忽略不計,包括在你的榜樣。由於pFoo的初始化在該範圍內,編譯器知道pFoo->bar必須意味着FooDerived :: bar,並且不需要檢查vtable。還有幾種緩存技術可以避免從簡單到複雜的多種vtable查詢。

4

即使在您展示的情況下,我懷疑任何編譯器都會按照您的建議進行操作。

您正在一個文件中使用一個非常簡單的程序。

想象一下,在Foo.h和Foo.cpp中有FooBase和FooDerived,而在main.cpp中有main。編譯Foo.cpp時,編譯器如何知道在整個程序中不需要vtbl。它沒有看到main.cpp。

最終確定只能在鏈接時進行,當它是太晚而複雜的修改目標文件,發現所有的電話爲sizeof(FooDerived)等

+0

進一步詳細說明,FooBase和FooDerived類不能有多個版本(內存佈局),或者不同的編譯單元可能不兼容。因爲有可能從非常見的基本指針調用的虛擬函數,所以編譯器必須爲vtable分配空間,這意味着vtable必須存在於該對象的所有實例中 - 即使在您的示例中也是如此。 – 2010-02-25 17:59:27

0

即使是最現代的,全球優化的編譯器仍然堅持「獨立翻譯」的原則。根據這一原則,每個翻譯單元都是獨立編寫的,而不需要了解整個最終程序中可​​能存在的任何其他翻譯單元。

當您聲明具有外部鏈接的類時,此類可用於其他翻譯單元。編譯器不知道您的類如何在其他翻譯單元中使用。因此,它必須假定該類的每個實例通常需要在構建時正確初始化其虛擬表指針。

在您的示例中,智能編譯器可能會發現*pFoo對象的動態類型爲FooDerived。這將允許編譯器優化代碼:直接調用FooDerived::bar函數以響應pFoo->bar()表達式(不使用虛擬表)。但是,編譯器通常仍然必須正確初始化每個對象中的虛擬表指針。

0

當編譯器知道將要調用哪個精確類的方法時,它可能會削減虛擬函數調用的間接開銷。這是指向分析的結果,該分析優化了編譯器。它們跟蹤指針變量的數據流,並且指針只能指向一種類型的對象的任何地方,它都可以生成正確類型的調用,靜態地(即在編譯時)實現虛擬調用語義。如其他許多人所說,除非編譯器正在進行全程序/鏈接時間優化(變得越來越流行; GCC在4.5版中獲得它),它仍然需要生成某種虛擬函數表來支持單獨的彙編。

相關問題