爲什麼C++沒有爲具有至少一個其他虛函數的類默認爲虛擬析構函數?在這種情況下,添加一個虛擬析構函數並不會花費任何代價,並且沒有一個是(幾乎?)總是一個錯誤。 C++ 0x會解決這個問題嗎?爲什麼析構函數在默認情況下不是虛擬的[C++]
回答
你不支付你不需要的東西。如果你永遠不會通過基指針刪除,你可能不需要間接析構函數調用的開銷。
也許你認爲只有vtable的存在是唯一的開銷。但是也必須考慮每個單獨的函數調度,如果我想直接使析構函數調用調度,我應該允許這樣做。
如果你曾經刪除過一個基本指針,並且該類有虛擬方法,那麼你的編譯器會警告你。
編輯:讓我在這裏拉西蒙的優秀評論:查看this SO question關於爲析構函數生成的代碼。正如你所看到的,還有代碼膨脹開銷需要考慮。
由標準的信件,具有非虛擬析構函數的多態類不是一個錯誤。對這樣一個對象執行的一個具體操作導致了未定義的行爲,但其他一切都完全是猶太教。因此,鑑於標準在程序員可以犯的錯誤方面的寬鬆行爲,爲什麼應該對析構函數進行特殊處理?
而且這樣的改變會產生成本,儘管大部分都是微不足道的:虛擬表將會增大一個元素,並且與析構函數調用相關的虛擬調度。
據我所知,不,在C++ 11中,這方面的析構函數的行爲沒有變化。我想它會在關於特殊成員函數的章節中說些什麼,但它並沒有,在虛擬函數的部分中一般也沒有。
有沒有*有*計劃使虛擬析構函數成爲C++ 0x中的默認值?我問,因爲我遇到了這篇論文:http://www2.research.att.com/~bs/C++0x_panel.pdf,它說底部是,但我一直沒能找到更多的信息關於它。 – jeffythedragonslayer
@dacode:我沒有按照實際的會議和什麼,所以我不知道。在四個「尷尬」中,只有最後一個實際上發生了變化。如果有人爲這種改變提交了proprosal,我不會感到驚訝,但爲什麼它被拒絕了,我不能說。 –
下面是一個例子(不,我建議寫這樣的代碼):
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 }
)。然而,由於這種技術已經支付了一些間接工作的成本,所以一些用戶可能不希望爲他們的基類使用虛擬析構函數。這就是「只支付你所需要的」的意思。
- 1. 默認情況下是虛擬的成員函數嗎?
- 2. 在什麼情況下C++析構函數不會被調用?
- 3. 以下哪種情況下需要虛擬析構函數?
- 4. 默認情況下,Java構造函數是不是公共的?
- 5. 爲什麼QWidget的析構函數不是虛擬的?
- 6. C++中的虛擬默認析構函數
- 7. C++虛擬析構函數
- 8. C++虛擬析構函數
- 9. 默認情況下,爲什麼不打包結構?
- 10. 爲什麼`boost :: multi_array_ref`的析構函數是非虛擬的?
- 11. 爲什麼默認情況下,varibale在c中聲明爲static?
- 12. 爲什麼Run.Text在默認情況下是雙向綁定的?
- 13. 默認情況下,函數參數是c#中的值類型
- 14. 沒有虛擬構造函數但是虛擬析構函數
- 15. 爲什麼Map在默認情況下在Scala中不可變?
- 16. 爲什麼Multicore JIT不在默認情況下在.net 4.5中?
- 17. 做默認析構函數做什麼?
- 18. 成員函數默認是虛擬的
- 19. 爲什麼我們有一個虛析構函數,而不是在C虛擬構造++?
- 20. 虛擬析構函數的默認覆蓋
- 21. 在什麼情況下,虛擬基礎析構函數仍可能導致內存泄漏而不被調用?
- 22. 爲什麼默認情況下Java方法/構造函數參數不是最終的?
- 23. 默認情況下,toJSON中包含Mongoose虛擬字段:schemaOptions.toJSON.virtuals = true;還不包括默認的虛擬域
- 24. 爲什麼虛擬表只有在虛擬功能的情況下才需要?
- 25. 默認情況下,爲什麼不在Windows上安裝Python?
- 26. 正確放置在默認的純虛析構函數C++ 11
- 27. 在沒有默認構造函數的情況下使用nhibernate
- 28. 爲什麼'虛擬'繼承不是默認行爲?
- 29. 爲什麼在繼承使用虛擬析構函數
- 30. 默認的默認構造函數,爲什麼不是用戶提供的默認構造函數?
該關鍵字是「幾乎」。如果您的基地具有虛擬功能,而您不想爲虛擬析構函數付費,那麼您如何在這個新世界中指定它不是虛擬的。所有舊代碼都會發生什麼?我們需要一個計劃來處理向後兼容性問題。 –
對於所有派生類,虛擬析構函數都有成本,因爲它需要析構函數代碼的另一個副本。見[這個問題](http://stackoverflow.com/questions/6613870/gnu-gcc-g-why-does-it-generate-multiple-dtors/6614903)。 –
可能的重複[爲什麼不具有虛擬的所有功能在CPP](http://stackoverflow.com/questions/6606657/why-not-have-all-the-functions-as-virtual-in-cpp) – iammilind