2012-12-18 97 views
2

考慮下面的代碼:空基類建設開銷?

#include <iostream> 
#include <type_traits> 

class Base 
{ 
    public: static int f() {return 42;} 
}; 

class Derived : public Base 
{ 
    protected: int x; 
}; 

class NotDerived 
{ 
    protected: int x; 
}; 

int main() 
{ 
    std::cout<<sizeof(Base)<<std::endl; 
    std::cout<<sizeof(Derived)<<std::endl; 
    std::cout<<sizeof(NotDerived)<<std::endl; 
    return 0; 
} 

隨着克++ 4.7 -O3,它打印:

1 
4 
4 

,如果我明白很好,這意味着空基類優化被啓用。

但我的問題涉及到運行時開銷:有沒有什麼開銷創建(和銷燬)相比NotDerived對象Derived對象因事實Derived要建設/破壞相應Base對象?

+0

我會這樣想,但我也不認爲你應該擔心它。你應該使用適合你工作的工具。在性能分析階段處理任何優化。 – RonaldBarzell

+0

這是我的代碼的關鍵方面。使用空的基類會對設計有很大的幫助,但是由於我在高性能計算領域工作,並且在執行過程中會創建數十億個此類對象,所以我應該關心它... – Vincent

+0

您應該關心,但對我而言,問題是你是否應該早點關心這件事?既然你有數字,你有沒有做過一些預測,看看你會在哪裏?看起來,如果從一開始就擔心這麼多問題,最好的辦法是爲最大可接受命中率提供硬編碼,然後將它們與編譯器進行比較,並記住不同的編譯器會產生不同的結果。 .. – RonaldBarzell

回答

3

雖然該標準沒有保證那裏,我會考慮一個編譯器,做一些不同的情況下,略有缺陷。

從字面上有什麼工作要做,以初始化基:無記憶必須進行初始化,無虛調用機制有待建立。不應該爲它生成代碼。

但是,您應經常檢查一些裝配在一個不平凡的設置,如果這對你真的很重要。

2

對此的任何答案將取決於實現,因爲該標準僅指定了語義。

但是,隨着任何現代編譯器和優化打開,我希望看到沒有任何區別。

有沒有額外的內存分配,沒有額外的代碼運行,沒有虛函數表指針作爲額外的基礎不是虛擬的建設過程中更改。您的DerrivedNotDerrived構造函數很可能是指令相同的指令。

關閉所有優化後,您可能會在某些平臺上調用空的Base::Base()函數,但您確實不應該擔心未優化的版本的性能。


我已經把一個小演示上gcc.godbolt.org:http://tinyurl.com/cg8ogym

總之

extern void marker______________________________________(); 
    // ... 
    marker______________________________________(); 
    new NotDerived; 
    marker______________________________________(); 
    new Derived; 
    marker______________________________________(); 

編譯成

call marker______________________________________()@PLT 
movl $4, %edi 
call operator new(unsigned long)@PLT 
call marker______________________________________()@PLT 
movl $4, %edi 
call operator new(unsigned long)@PLT 
call marker______________________________________()@PLT 

如果切換過來叮噹聲,它甚至會優化內存分配

0
#include <type_traits> 
#include <unistd.h> 

class SlowBase 
{ 
    SlowBase() { ::sleep(5); } 

    public: static int f() {return 42;} 
}; 
static_assert(std::is_empty<SlowBase>::value , "SlowBase is empty"); 

Base類需要五秒鐘以構建 !!

#include <type_traits> 

class FatBase 
{ 
    FatBase() = default; 
    int data[1024*1024];  
    public: static int f() {return 42;} 
}; 
static_assert(!std::is_empty<FatBase>::value , "FatBase is not empty"); 

但是這一個沒有時間!

我的觀點是施工開銷與班級的大小無關,這與建造者做什麼有關。SlowBase是一個空類,但構建起來非常緩慢。 FatBase是一個兆字節的大小,但甚至沒有將數組元素歸零,所以沒有任何關係。

在你的Base例子中有一個隱式聲明的,簡單的默認構造函數,所以它沒有任何關係。