如何解决重载运算符在基类中删除
| 根据C ++标准(ISO / IEC 14882:2003(E))§12.5.4,关于重载operator delete
:
如果delete-expression以一元::运算符开头,则在全局范围内查找释放函数的名称。否则,如果使用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 :: operator delete()释放。
看完这篇文章,我想知道...
所有主要的C ++编译器(MSVC ++,GCC)是否都完全支持该标准的一部分?
如果是这样,他们是如何做到的?隐藏的虚拟功能? “特殊”虚拟析构函数调用? RTTI?
使用标准中的示例:如果在单独的EXE / DLL / DSO中定义了f()和D :: operator delete()是否会出现问题? (当然,假设所有内容都使用同一编译器进行编译)
§5.3.5.5也可能是相关的:
在第一个替代方案(删除对象)中,如果操作数的静态类型与动态类型不同,则静态类型应为操作数动态类型的基类,并且静态类型应具有虚拟析构函数或行为是不确定的。在第二种选择(删除数组)中,如果要删除的对象的动态类型与静态类型不同,则行为是不确定的。
解决方法
我对VC ++ ABI知之甚少,但是Itanium ABI有充分的文档记录。
抬头看名字处理方案,看到的是:
<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
是非虚拟的,由于它是从虚拟析构函数调用的,因此对于所有效果和用途,都可以将其视为虚拟的。
, 在深入研究GCC 4.8发出的汇编代码后
GCC将生成两段代码(对于析构函数为虚拟的类):
One is assembly snippet#1 for {Destructor + Dealloc}
The other is assembly snippet#2 for {Destructor only}
对于析构函数不是虚拟的类,将在调用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
因此,解除分配功能与虚拟析构函数绑定在一起。
因此,我认为这将回答您有关如何实现释放分配功能(如虚拟还是静态)的问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。