2012-04-16 56 views
1

刪除對象多態

Base* optr=new Derived(); 

delete optr; 

我知道,如果基類有一個非虛析構函數,只有〜庫()的析構函數將被稱爲刪除optr指針時。但是我發現,即使沒有〜Derived()析構函數被調用,被派生對象所佔用的內存也被釋放了。所以我的問題是一個對象可以釋放而不調用它的析構函數?

如果答案是,如果我的派生類不包含任何動態分配的變量,我可以使用非虛擬析構函數,所以我不在乎它是否未被調用?

回答

4

從標準C++的角度來看,答案很簡單:結果是不確定的行爲,所以你得到的是完全不可預知

我有點疑惑,爲什麼你反正不在乎。如果您可以從類中刪除虛擬函數,則每個實例都會變小(按vtable指針的大小)。使用這樣的事物作爲基類很少有意義 - 儘管用作基類是明智的,但基類中至少需要一個虛函數才能覆蓋派生類。一旦你有一個虛擬函數(任何虛函數),添加更多的實質上是免費的 - 通過添加更多的虛函數,對象不會變大。

要直接回答你的問題:是的,沒有調用析構函數就可以釋放內存。真正的問題是當你做到這一點時會發生什麼(而且這個問題真的沒有答案)。

1

可能能夠逃脫不虛析構函數,如果派生類中不添加任何成員。內存佔用將相同,並且成員將全部在基類析構函數中被銷燬。然而,這不是標準保證的,你會受到編譯器實現的支配。

+0

在* mights *的列表中,還有其他一些情況,例如派生類型不能有'operator delete'定義...(即如果它有一個,那麼除非析構函數是虛擬的,否則它不會被調用)。我曾在消息中看到一個小孩不小心用魚叉從頭部開槍,並沒有受到任何傷害,所以你可能不會用魚叉射擊自己,但我不會推薦這樣做。 .. – 2012-04-16 16:58:14

+0

@大衛,我不玩魚叉,所以我很安全!說真的,我從來沒有使用'operator delete',我從來沒有見過其他人使用它。 – 2012-04-16 17:07:00

1

這裏有兩種不同的東西:調用對象的析構和釋放內存。

標準堆規範不要求您在釋放內存塊大小時傳遞內存塊大小。也就是說,堆實現應該推導出內存塊大小本身。

因此 - 。如果Derived不包含必須通過適當方式銷燬的額外事物(例如分配在堆上的內存,文件句柄等) - 您不需要虛擬析構函數。

2

有關未定義行爲的事情是,有時似乎工作

該標準不說,如果基類的析構函數不是虛擬程序必須失敗,它說,它必須工作當析構函數虛。