从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