2011-07-08 79 views
23

爲什麼C++沒有爲具有至少一個其他虛函數的類默認爲虛擬析構函數?在這種情況下,添加一個虛擬析構函數並不會花費任何代價,並且沒有一個是(幾乎?)總是一個錯誤。 C++ 0x會解決這個問題嗎?爲什麼析構函數在默認情況下不是虛擬的[C++]

+2

該關鍵字是「幾乎」。如果您的基地具有虛擬功能,而您不想爲虛擬析構函數付費,那麼您如何在這個新世界中指定它不是虛擬的。所有舊代碼都會發生什麼?我們需要一個計劃來處理向後兼容性問題。 –

+4

對於所有派生類,虛擬析構函數都有成本,因爲它需要析構函數代碼的另一個副本。見[這個問題](http://stackoverflow.com/questions/6613870/gnu-gcc-g-why-does-it-generate-multiple-dtors/6614903)。 –

+0

可能的重複[爲什麼不具有虛擬的所有功能在CPP](http://stackoverflow.com/questions/6606657/why-not-have-all-the-functions-as-virtual-in-cpp) – iammilind

回答

19

你不支付你不需要的東西。如果你永遠不會通過基指針刪除,你可能不需要間接析構函數調用的開銷。

也許你認爲只有vtable的存在是唯一的開銷。但是也必須考慮每個單獨的函數調度,如果我想直接使析構函數調用調度,我應該允許這樣做。

如果你曾經刪除過一個基本指針,並且該類有虛擬方法,那麼你的編譯器會警告你。

編輯:讓我在這裏拉西蒙的優秀評論:查看this SO question關於爲析構函數生成的代碼。正如你所看到的,還有代碼膨脹開銷需要考慮。

2

由標準的信件,具有非虛擬析構函數的多態類不是一個錯誤。對這樣一個對象執行的一個具體操作導致了未定義的行爲,但其他一切都完全是猶太教。因此,鑑於標準在程序員可以犯的錯誤方面的寬鬆行爲,爲什麼應該對析構函數進行特殊處理?

而且這樣的改變會產生成本,儘管大部分都是微不足道的:虛擬表將會增大一個元素,並且與析構函數調用相關的虛擬調度。

據我所知,不,在C++ 11中,這方面的析構函數的行爲沒有變化。我想它會在關於特殊成員函數的章節中說些什麼,但它並沒有,在虛擬函數的部分中一般也沒有。

+0

有沒有*有*計劃使虛擬析構函數成爲C++ 0x中的默認值?我問,因爲我遇到了這篇論文:http://www2.research.att.com/~bs/C++0x_panel.pdf,它說底部是,但我一直沒能找到更多的信息關於它。 – jeffythedragonslayer

+1

@dacode:我沒有按照實際的會議和什麼,所以我不知道。在四個「尷尬」中,只有最後一個實際上發生了變化。如果有人爲這種改變提交了proprosal,我不會感到驚訝,但爲什麼它被拒絕了,我不能說。 –

2

下面是一個例子(不,我建議寫這樣的代碼):

struct base { 
    virtual void foo() const = 0; 
    virtual void bar() const = 0; 
}; 

struct derived: base { 
    void foo() const {} 
    void bar() const {} 
}; 

std::shared_ptr<base> 
make_base() 
{ 
    return std::make_shared<derived>(); 
} 

這完全是精碼不顯示UB。這是可能的,因爲std::shared_ptr使用類型擦除;最後致電delete的電話將刪除derived*,即使觸發銷燬的最後std::shared_ptr屬於std::shared_ptr<void>類型。

請注意,std::shared_ptr的這種行爲是而不是適合虛擬銷燬;它有多種其他用途(例如std::shared_ptr<FILE> { std::fopen(...), std::fclose })。然而,由於這種技術已經支付了一些間接工作的成本,所以一些用戶可能不希望爲他們的基類使用虛擬析構函數。這就是「只支付你所需要的」的意思。

相關問題