2010-01-20 66 views
17

給定兩個類只有原始數據類型,沒有自定義析構函數/釋放器。 C++規範是否保證它將釋放正確的大小?使用帶有基類指針的delete會導致內存泄漏嗎?

struct A { int foo; }; 
struct B: public A { int bar[100000]; }; 
A *a = (A*)new B; 
delete a; 

我想知道我需要寫一個空的virtual dtor?

我試過g ++和vC++ 2008,它們不會造成泄漏。但是我想知道C++標準中什麼是正確的。

+1

當我將內存池中的虛擬方法與繼承混合在一起時,我的生活中出現了最嚴重的錯誤。只是不這樣做,這是不安全的。 – vava 2010-01-20 10:38:54

回答

23

除非基類析構函數是虛擬的,否則它是未定義的行爲。見5.3.5/4:

如果靜態類型[刪除操作員的]的操作數是從它的動態類型不同,靜態類型應爲基類操作數的動態型的和靜態型應該有一個虛擬析構函數或行爲未定義。

+0

位於[n3242](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3242.pdf),位於5.3.5/** 3 **。沒有答案解釋如果你有一個虛擬析構函數會發生什麼。我們是否只擔心這裏的析構函數?拋開解構器,實際的子類是否會從內存中「移除」?如果是這樣,那麼不需要析構函數的子類就不會泄漏。 – 2013-06-22 05:36:19

+1

@Nathan:如果基類有一個虛擬析構函數,一切正常。否則,行爲是不確定的。 當存在一個虛擬析構函數時,所有的析構函數都會被調用(鏈中的每個派生類都有一個虛擬析構函數,即使它沒有被聲明爲虛擬的或者根本沒有被明確定義)並且內存被清除。 – 2014-01-30 12:59:47

16

根據C++標準,你有什麼是未定義的行爲 - 這可能表現爲泄漏,它可能不會,爲了你的代碼是正確的,你需要一個虛擬析構函數。

此外,您不需要(A *)強制轉換。每當你發現自己在C++中使用C風格的轉換,你可以相當肯定它是不必要的,或者你的代碼是錯誤的。

0

它將以正確的大小釋放,因爲要釋放的大小是您獲得的堆內存區域的屬性(沒有大小傳遞給類似free()的函數!)。

然而,沒有德爾託被稱爲。如果'B'定義了析構函數或者包含具有非平凡析構函數的成員,它們將不會被調用,從而導致潛在的內存泄漏。但是,您的代碼示例中不是這種情況。

+1

你在哪裏看到「免費功能」? C++使用'delete' __operator__而不是函數的原因之一是直接編譯器實現。編譯器_does_知道sizeof(A)',它也知道A沒有虛擬析構函數,所以它可以在後臺調用'FourBytePool :: free(void * p)'。 – MSalters 2010-01-21 11:08:27

1

這是未定義的行爲 - 也許一切都很好,也許whetever出錯了。要麼不這樣做,要麼爲虛擬析構函數提供基類。

在大多數實現中,這不會泄漏 - 類中沒有堆分配成員函數,因此delete完成時唯一需要的是釋放內存。取消分配內存只使用對象的地址,僅此而已,其餘的都是堆。

1

對於只有原始數據我相信你很好。在這種情況下,您可能合法地不想承擔v-表的成本。否則,虛擬遊戲絕對是首選。