從C++標準(ISO/IEC 14882:2003(E)),§12.5.4,約超載operator delete
:重載操作者刪除在基類
如果delete表達式與一元開始::運算符,解除分配函數的名稱在全局範圍內查找。否則,如果使用delete-expression來取消分配其靜態類型具有虛擬析構函數的類對象,則釋放函數是動態類型的虛擬析構函數(12.4)的定義中的查找找到的函數。否則,如果使用delete-expression來釋放類T或其數組的對象,則該對象的靜態和動態類型應該相同,並且在T的範圍內查找解除分配函數的名稱。如果此查找失敗找到名字,名字在全球範圍內查找。如果查找結果不明確或無法訪問,或者查找選擇了位置釋放函數,則該程序不合格。
§12.5.7也很有意思:
由於成員分配和釋放函數是靜態的,他們不能是虛的。 [注意:但是,當delete-expression的cast-expression引用類類型的對象時,因爲實際調用的釋放函數是在作爲對象的動態類型的類的範圍內查找的,所以如果析構函數是虛擬的,效果是一樣的。例如,
struct B {
virtual ˜B();
void operator delete(void*, size_t);
};
struct D : B {
void operator delete(void*);
};
void f()
{
B* bp = new D;
delete bp; // uses D::operator delete(void*)
}
在這裏,存儲用於d類的非陣列目的通過d釋放::操作者刪除(),由於虛擬析構函數。]
看完這個,我想知道...
- 這是標準的一部分,由所有主要的C++編譯器(MSVC++,GCC)完全支持?
- 如果是這樣,他們是怎麼做到的?隱藏的虛擬功能? 「特殊」虛擬析構函數調用? RTTI?
- 使用標準示例:如果f()和D :: operator delete()在單獨的EXE/DLL/DSO中定義,那麼會出現問題嗎? (假設一切都使用相同的編譯器進行編譯,當然)
§5.3.5.5也可能是相關的:
在第一種方式(刪除對象),如果靜態類型的操作數與其動態類型不同,靜態類型應該是操作數動態類型的基類,靜態類型應該具有虛擬析構函數或行爲未定義。在第二種選擇(刪除數組)中,如果要刪除的對象的動態類型與其靜態類型不同,則行爲是未定義的。
我的猜測:他們走虛擬表。正如標準所說,這個類需要有一個虛擬析構函數以正確的方式工作。對於非重載版本的「delete」也是如此。 – Xeo 2011-06-15 09:14:39
我試着回答,但看起來你真正想要的是讓別人查看GCC源代碼並向你報告。我想你可以自己做。 – littleadv 2011-06-15 09:45:39