来自C ++标准(ISO / IEC 14882:2003(E)),§12.5.4,关于重载operator delete
:
如果delete-expression以unary :: operator开头,则在全局范围内查找释放函数的名称。否则,如果使用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 :: operator delete()释放了D类非数组对象的存储空间。]
看完之后,我想知道......
§5.3.5.5也可能是相关的:
在第一个备选(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或者行为未定义。在第二种方法(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为是未定义的。
答案 0 :(得分:6)
我对VC ++ ABI知之甚少,但Itanium ABI已有详细记载。
查看the name mangling scheme,请看:
<ctor-dtor-name> ::= C1 # complete object constructor
::= C2 # base object constructor
::= C3 # complete object allocating constructor
::= D0 # deleting destructor
::= D1 # complete object destructor
::= D2 # base object destructor
感兴趣:D0 # deleting destructor
,这意味着即使delete
是非虚拟的,因为它是从虚拟析构函数调用的,所以它可以被视为虚拟的所有效果和目的。
答案 1 :(得分:0)
通过GCC 4.8挖掘汇编代码后
GCC将生成两段代码(对于析构函数为虚拟的类):
One is assembly snippet#1 for {Destructor + Dealloc}
The other is assembly snippet#2 for {Destructor only}
对于析构函数不是虚拟的类,调用deallocation函数指令将在你调用delete的位置生成。
(以下讨论假设析构函数是虚拟的) 所以对于以下代码:
delete C // This will be translate as call snippet#1 for the correct dynamic type
如果您的代码如下:
p->C::~C() // this will be translate to call snippet#2
因此deallocate函数与虚拟析构函数绑定在一起。 所以我认为这将回答你关于如何实现deallocate功能的问题,如虚拟但也是静态的。