9

在学习我的语言时,我遇到了一个有趣的流程控制场景。如果在处理break语句时抛出异常会发生什么。GCC 似乎认为中断流程丢失了,但标准似乎对应该发生的事情保持沉默。

例如,下面的程序实际上应该做什么?

#include <iostream>
using namespace std;

struct maybe_fail {
    bool fail;
    ~maybe_fail() {
        if( fail )
            throw 1;
    }
};

int main() {
    for( int i=0; i < 6; ++i ) {
        cout << "Loop: " << i << endl;

        try {
            maybe_fail mf;
            mf.fail = i % 2;
            if( i == 3 )
                break;

        } catch( int ) {
            cout << "Caught" << endl;
        }
    }
    return 0;
}

请注意, areturn也将被阻止, a 也将被阻止continue(在 catch 之后添加输出以查看)。试图goto在街区外的尝试也会被抓住。

什么是正确的流程?该标准似乎没有解决这个问题:关于跳转语句的第 6.6 节没有提及,关于异常处理的第 15 节也没有提及。我确实理解析构函数中的异常形式非常糟糕,但是如果您将 BOOST_SCOPE_EXIT 之类的东西用于 defer 语句,则此行为可能变得非常重要。

也许有趣的是,Java 和 Python 中也发生了相同的流程,因此至少在命令式语言中似乎存在一些一致性。

4

2 回答 2

4

这在 15.1 抛出异常中有所介绍:

2 当抛出异常时,控制权转移到最近的具有匹配类型的处理程序(15.3);“最近的”是指 try 关键字后面的复合语句或 ctor-initializer 最近由控制线程进入但尚未退出的处理程序。

一旦控制转移到异常处理程序,它就会从那里继续。没有机制可以“记住”代码在 a 中间,break然后在处理异常后以某种方式恢复。

于 2013-04-19T04:10:14.803 回答
0

鉴于标准中的具体措辞,我要说它是模棱两可的。文本不足以确定这些情况的预期流程。由于编译器的编写方式,我们现在拥有的约定很可能只是偶然的。

请参阅我的博客主题如何捕获“返回”语句

于 2013-05-09T10:22:58.407 回答