为什么删除的析构函数除了普通的析构函数之外还占用第二个vtable插槽?

问题描述 投票:0回答:1

在以Itanium C++ ABI为模型的C ++ ABI实现中,后面跟随着许多其他处理器的ABI,虚拟析构函数实际上占据了两个vtable插槽。除了可以完成您期望的“完整对象析构函数”之外,还有“删除析构函数”的第二个条目,它调用第一个条目,然后删除该对象的内存。

这种方法存在问题,在小型内存系统中可能是个麻烦:即使没有其他代码使用动态内存管理器,也已链接了该动态内存管理器。当没有调用删除应用程序中的任何位置时,这是死代码。这是因为C ++编译器/链接器通常无法检测到未从任何地方调用vtable中的插槽,因此无法删除关联的代码。显然,最好以不涉及vtable条目的其他方式实现删除析构函数,并且允许编译器/链接器忽略此无效代码。

当然,可以实现自定义void operator delete(void *) {}以防止链接程序引入动态内存代码,但这仍然不能阻止删除的析构函数代码完全发出。

因此,我的问题:没有更好的方法来实现删除析构函数?我的想法是将指针返回到内存块的开头,以从完整的对象析构函数中删除。如果要在销毁后删除存储块,则此返回的地址可以由调用operator delete的非虚拟函数使用。本质上,拥有由完整的对象析构函数返回的内存地址将允许删除的析构函数是非虚拟的,因此有资格消除死代码。

但是我想我一定已经忽略了某些东西,这使得这个相当简单的解决方案变得不可能。但是那会是什么呢?有人可以帮我详细说明Itanium ABI中的设计决策吗?

c++ memory-management linker virtual-destructor itanium
1个回答
0
投票

与破坏类时的正常虚拟函数不同,必须以正确的顺序调用其析构函数及其所有父代的析构函数。

技术上可以将所有函数调用组合为一个函数调用,但是需要了解每个析构函数的实现或对象的完整结构。基本上取消呼叫的虚拟化。编译器并不擅长于此。不太确定所有细节,因为考虑到所有可能的过度虚拟对象,这是一个非常复杂的问题。

© www.soinside.com 2019 - 2024. All rights reserved.