【问题标题】:Throwing during unwinding -- why does this example work?在展开期间投掷——为什么这个例子有效?
【发布时间】:2011-11-11 07:10:39
【问题描述】:

考虑一下:

void thrower () {
    throw "123";
}

struct Catcher {
    ~ Catcher () {
        try {thrower ();}
        catch (...) {}
    }
};

int main () {
    try {
       Catcher c;
       throw 1.23;
    }
    catch (...) {}
}

在 gcc 4.3 上无需调用 terminate 即可编译和运行,但 according to the standard (15.5.1)

...当异常处理机制在完成对要抛出的表达式的评估之后但在捕获异常之前 (15.1),调用通过未捕获异常退出的用户函数...应调用终止。

~Catcher 在 double 被抛出后被调用时,这是“在完成评估之后......在异常被捕获之前”,thrower 是“一个通过未捕获的异常退出的用户函数”,这满足上述条件。是的,char* 被捕获,但仅在 用户函数退出之后。

不应该调用terminate 吗?

强调这一点:

void do_throw () {
    throw "123";
}

void thrower () {
    do_throw ();
    // Uncaught exception here (A)
}

struct Catcher {
    ~ Catcher () {
        try {thrower (); /* (B) */}
        catch (...) {}
    }
};

int main () {
    try {
       Catcher c;
       throw 1.23;
    }
    catch (...) {}
}

(A) 发生在 (B) 的上下文中,它已经有一个异常在进行中。

那么,terminate 不应该被调用吗?如果不是,而且在这种情况下,我们可以同时有两个例外,那么我们在哪里划清界限?

【问题讨论】:

    标签: c++ exception gcc terminate


    【解决方案1】:

    为什么应该调用terminate?您有一个捕获所有异常的 catch(...) 块:一个捕获 doublemain 中的那个),另一个捕获 char const[4]~Catcher 中的那个)。

    因此没有函数“以未捕获的异常退出”,因为所有异常都已被捕获。

    这里的关键词是“调用以未捕获异常终止的用户函数”。这与“调用用户函数,该用户函数在某处调用用户函数,该函数以未捕获的异常终止。”如果你调用一个函数并且它里面有一个try/catch 块,然后你调用了一些以异常终止的函数但是你捕获了这个异常,terminate 不会被调用。

    tl;dr:调用层次结构中的第一个调用,在异常评估之间和捕获之前必须退出,并出现异常以调用terminate不是 em> 第一次调用下面的分支。这是有道理的,因为您无法在评估抛出的对象和捕获它之间设置 另一个 catch 块。

    【讨论】:

    • 他要问的问题是,虽然 1.23 被抛出但尚未被捕获,但另一个函数称为 throwing 123,它未被该函数本身捕获。所以根据标准,应该调用terminate。
    【解决方案2】:

    不同的重点:

    异常处理机制,在完成对要抛出的表达式的评估之后但在捕获异常之前(15.1),调用一个用户函数,该函数通过未捕获的异常...应调用终止

    thrower()是一个用户函数,通过异常退出,但不被异常处理机制调用;它由另一个用户函数(Catcher 的析构函数)调用,该函数本身由异常处理机制调用,并且此函数不会通过异常退出。

    【讨论】:

      【解决方案3】:

      异常处理机制调用的哪个函数通过 未捕获的异常。异常处理调用的唯一函数 这里的机制是Catcher::~Catcher(),它正常退出,通过 到达函数的末尾。

      而且基本上同时的数量是没有限制的 活动异常。限制是必须的例外的数量 向上传播到给定点。如果Catcher::~Catcher() 退出 通过一个异常,我们将有两个异常向上传播,一个 它触发了析构函数的调用,以及 析构函数退出。只要析构函数捕获所有异常, 并且不传播它们,没有问题。

      【讨论】:

        【解决方案4】:

        ...当异常处理机制,完成评估后 在捕获异常之前要抛出的表达式 (15.1),调用通过未捕获异常退出的用户函数...... 应调用终止。

        异常处理机制调用~Catcher(),不会通过未捕获的异常退出;因此它不调用std::terminate。它不会(直接)调用thrower()

        【讨论】:

        • ~Catcher 不会通过未捕获的异常退出,但 thrower 会退出
        • 这听起来很对。 “调用函数”不是递归定义的,它只是指当前上下文。
        • @spraff:是的,但是异常处理机制没有调用thrower()。它只调用~Catcher()
        【解决方案5】:

        这是完全合法的代码。在引发问题之前,您正在捕获所有抛出的东西。 仅当您删除 ~Catcher 中的 try/catch 时,您才会在展开期间抛出异常。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-05-28
          • 2012-12-23
          • 2017-08-31
          • 1970-01-01
          • 1970-01-01
          • 2022-08-06
          • 2017-09-28
          • 2020-10-19
          相关资源
          最近更新 更多