首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从析构函数抛出异常对vtable安全吗?

从析构函数抛出异常对vtable安全吗?
EN

Stack Overflow用户
提问于 2015-12-01 04:16:00
回答 3查看 777关注 0票数 17

请考虑以下示例:

代码语言:javascript
复制
#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指向的object B,因为这是非常合乎逻辑的,异常将“取消”(如果安全地编程)析构函数的效果。但是当我尝试在gdb中运行这段代码并到达catch部分的断点时,我发现B对象不见了,只剩下一个基本对象,因为vtable看起来像这样:

代码语言:javascript
复制
(gdb) i vtbl b
vtable for 'A' @ 0x400cf0 (subobject @ 0x603010):
[0]: 0x0
[1]: 0x0
[2]: 0x4008e0 <__cxa_pure_virtual@plt>

我的问题:如果我强烈地想从析构函数抛出一个异常,有没有办法避免(半)破坏vtable?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-12-01 04:41:43

我一直认为(天真的我),在这种情况下,当程序进入

段时,那么b指向的对象B将是完好无损的,因为非常合乎逻辑的是,异常将“取消”(如果安全地编程)析构函数的效果。

这不是真的。该标准说:

一个具有任意存储时间的对象,其初始化或销毁被异常终止,它将为其所有完全构造的子对象(不包括类联合的变量成员)执行析构函数,即对于主体构造函数(12.6.2)已完成执行而析构函数尚未开始执行的子对象执行析构函数。

(15.2/2 in N4140)

也许更重要的是:

类型为T的对象的生命周期在以下情况下结束:

-如果T是具有非平凡析构函数的类类型(12.4),则开始析构函数调用

(3.8/1.3 in N4140)

由于b的每个成员和基础都是完全构造的,并且它们的析构函数没有进入,但它们将被认为是销毁的。因此,在您的catch b 块中,所指向的整个对象已经是死的。

这背后的理性可能是禁止“半销毁”对象,因为不能销毁的对象的状态应该是什么还不清楚。例如,如果只有一些成员已经被销毁了呢?

甚至标准本身也建议不要留下析构函数的异常。正如我在之前的评论中所写的,抛出析构函数是很奇怪的。

我们可以从上面的引用中得到一个很好的规则:当一个对象的构造函数是done而不抛出时,它就开始存在,只要它的析构函数开始执行,它就不存在了,无论它是如何退出的。(在标准中的其他地方,这一点被重申得更清楚。这是有例外的,不要关心它们。)

所以总而言之:

如果我强烈地想从析构函数抛出一个异常,有没有办法避免(半)破坏vtable?

不是的。一旦你进入析构函数,你的对象就完成了。

票数 17
EN

Stack Overflow用户

发布于 2015-12-01 04:56:49

在这种情况下,当程序进入

段时,那么对象B中的b点将是完好无损的,因为从逻辑上讲,异常将“取消”(如果安全地编程)析构函数的效果。

不是的。 when its destructor

不能取消析构函数。

正如其他人所说,在C++中抛出析构函数是很奇怪的,你想要避免它们except for special cases

票数 6
EN

Stack Overflow用户

发布于 2015-12-01 05:25:49

就实例而言,从析构函数抛出它是定义良好且安全的。您开始遇到问题的地方是数组(因为它无法完成数组的删除,并且您无法找回它)和catch子句(可能最终调用terminate)。如果析构函数抛出,编写异常安全代码也很困难(我认为这实际上是不可能的,但还没有准备好从内存中断言这一点)。

我曾经使用过抛出析构函数来做一些事情。例如,我使用的API可能会返回错误代码并分配错误blob。我写了一个小的作用域保护的东西,它会分发引用来放入数据,并在析构函数中检查错误条件。如果它看到一个异常,它会将其转换为异常并抛出它。

像这样的构造在技术上是安全的,但在你知道自己在做什么之前,你会想要避免它。您必须明确,这些内容不能存储在向量或数组中,并且可能会使异常安全代码不安全。主要的问题是,几乎每个人都希望所有的析构函数都是非抛出的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34007190

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档