【发布时间】:2016-03-04 14:17:57
【问题描述】:
请考虑以下示例:
#include <csignal>
class A
{
public:
virtual ~A() {}
virtual void foo() = 0;
};
class B : public A
{
public:
virtual ~B() { throw 5; }
virtual void foo() {}
};
int main(int, char * [])
{
A * b = new B();
try
{
delete b;
}
catch ( ... )
{
raise(SIGTRAP);
}
return 0;
}
我一直认为(天真)当程序在这种情况下进入catch 部分时,对象B 将在其中b 点将完好无损,因为异常将具有非常合乎逻辑“取消”(如果编程安全)析构函数的效果。但是当我尝试在 gdb 中运行这个 sn-p 并到达 catch 部分的断点时,我看到 B 对象已经消失,只剩下 A 基础对象,因为 vtable 看起来像这样:
(gdb) i vtbl b
vtable for 'A' @ 0x400cf0 (subobject @ 0x603010):
[0]: 0x0
[1]: 0x0
[2]: 0x4008e0 <__cxa_pure_virtual@plt>
我的问题:如果我非常想从析构函数中抛出异常,有没有办法避免(半)破坏 vtable?
【问题讨论】:
-
抛出析构函数很奇怪,尽可能避免。
-
抛出析构函数比怪异更糟糕。它们实际上是quite dangerous,几乎在所有情况下都应避免使用。
-
为什么要中止对象的销毁?你知道离开作用域意味着破坏本地对象吗?那么您是否希望编译器向上跳堆栈以避免破坏您的对象?你有没有注意到,清理资源的函数通常总是成功的——并且返回 void。