【发布时间】:2011-06-15 09:09:10
【问题描述】:
来自 C++ 标准 (ISO/IEC 14882:2003(E)),§12.5.4,关于重载operator delete:
如果删除表达式以一元 :: 运算符开头,则在全局范围内查找解除分配函数的名称。否则,如果 delete-expression 用于释放静态类型具有虚拟析构函数的类对象,则释放函数是在动态类型的虚拟析构函数 (12.4) 的定义中查找的函数。否则,如果删除表达式用于释放对象 类 T 或其数组,对象的静态和动态类型应相同,并在 T 范围内查找释放函数的名称。如果此查找未找到名称,则在全局范围内查找名称。如果查找的结果不明确或无法访问,或者查找选择了一个放置解除分配函数,则程序是非良构的。
§12.5.7 也很有趣:
由于成员分配和释放函数是静态的,它们不能是虚拟的。 [注意:但是,当删除表达式的强制转换表达式引用类类型的对象时,因为实际调用的释放函数是在作为对象的动态类型的类的范围内查找的,如果析构函数是虚的,效果是一样的。例如,
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::operator delete()释放。]
看完之后,我想知道......
- 所有主要 C++ 编译器(MSVC++、GCC)是否完全支持标准的这一部分?
- 如果是这样,他们是怎么做到的?隐藏虚函数? “特殊”虚拟析构函数调用? RTTI?
- 使用标准中的示例:如果在单独的 EXE/DLL/DSO 中定义 f() 和 D::operator delete() 会不会有问题? (当然,假设所有内容都是使用相同的编译器编译的)
§5.3.5.5 也可能是相关的:
在第一种选择(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。在第二种选择(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义。
【问题讨论】:
-
我的猜测:他们走的是虚拟桌子。正如标准所说,该类需要有一个虚拟析构函数才能以正确的方式工作。对于
delete的非重载版本也是如此。 -
我试图回答,但您似乎真正想要的是有人查看 GCC 源代码并向您报告。我想你可以自己做。