What's this extra parameter passed into virtual destructor?
我有这个代码:
1 2 3 4 5 6 7 8 9 10
| class Class {
public:
virtual ~Class() {}
};
int main()
{
Class* object = new Class();
delete object;
} |
我用VisualC++ 10编译并获得EDCOX1×0语句的反汇编:
1 2 3 4 5 6 7
| delete object;
test eax,eax
je wmain+23h (401041h)
mov edx,dword ptr [eax]
push 1
mov ecx,eax
call dword ptr [edx] |
对于实际的析构函数:
1 2 3 4 5 6 7 8 9 10 11 12
| Class::`scalar deleting destructor':
test byte ptr [esp+4],1
push esi
mov esi,ecx
mov dword ptr [esi],offset Class::`vftable' (402100h)
je Class::`scalar deleting destructor'+18h (401018h)
push esi
call dword ptr [__imp_operator delete (4020A8h)]
pop ecx
mov eax,esi
pop esi
ret 4 |
push 1在调用站点做什么?为什么test在析构函数入口点检查该值并有条件地绕过对operator delete()的调用?
- 我建议你把这个标记为c++-cli。
- 这是调试输出吗?
- @这就是我在Visual Studio反汇编窗口中看到的。
- Gorpik,但它不是C++ + CLI,我不认为
- 对,但这是调试项目配置还是版本?
- 请参阅[显示此类隐藏析构函数参数的含义的此答案][1]。[1]:stackoverflow.com/questions/7750280/…
- @托马斯麦克劳德:这是用/o2优化释放的。
- @鲁普:你完全正确。我严重误解了这个问题。
- test eax,eax正在检查空指针。不知道为什么它在发布代码中。
- @托马斯麦克劳德,你被明确地允许打电话给delete null;,有可能new返回了一个空值,所以可能不允许优化它。
- @ ThomasMcLeod:VisualC++在某些场合发出非常愚蠢的代码-非常代码是"删除空指针"NO-OP。
- @ RUP:确切地说,除了EDCOX1之外,3不返回EDCOX1×5 },VisualC++仍然检查它。
- @卢比,@sharp-现在有意义了。
- 无论new是否可以返回空值(如果与std::nothrow一起使用,则可以),delete仍然必须检查有人调用时的情况,即delete空值;
- @Nemanja Trifunovic:编译器拥有所有的代码,这样它就可以在没有nothrow的情况下使用new,因此不能返回空值,因此delete是在非空指针上完成的。可以取消检查,只是VisualC++没有这样做。
析构函数使用该参数来确定是否应在末尾调用delete。
3个不想称之为:
- 析构函数由派生类析构函数调用
- 对象是在堆栈上分配的,因此不是用new创建的。
- 对象是另一个对象的字段,因此不是由新对象创建的
编辑:添加第三个案例
基本上,虚拟析构函数也实现了调用操作符delete。参数在那里决定是否调用它。
请参阅显示此类隐藏析构函数参数含义的答案。
- 这个隐藏参数是VC++特有的吗?我认为GCC选择了生成多个析构函数的方法(3,如果我记得正确的话)。
- @Matthieum.:这应该是ABI的一部分,所以GCC在Windows上也应该这样做(如果它想兼容的话)。不过,我还没试过。
- @杰帕切莱克:啊,对,在阿比。实际上,GCC在Windows上也没有这个功能。只要你不尝试混合gcc和vc++库:)
- @Matthieum.:嗯,我以为他们试图实现二进制兼容(比如ICC),但似乎没有。
- 嗯,据我所知,它们在C级别上是兼容的:)
我相信这个额外的参数告诉编译器哪个析构函数是派生的最多的,所以它只在继承的适当级别上释放一次内存。如果我没记错的话,我在海湾合作委员会也看到过类似的情况。
- GCC为每个类发出3个析构函数:一个常规析构函数、释放析构函数和一个子类析构函数。看起来vs只是发出一个声音,然后用bool来称呼它。
- @技巧代码:谢谢你的评论:解释一些我一直在想的事情!