重新抛出异常

15
为什么以下代码无法处理重新抛出的异常?我尝试了所有的组合,但是没有一个能够在最后的catch中展示输出结果,所以我很困惑!
Derived D;

try {
       throw D;
} catch ( const Derived &d) {
       throw;
} catch (const Base &b) {
      cout << "caught!" << endl;
}

Derived D;

try {
    throw D;
} catch ( const Derived d) {
    throw;
} catch (const Base b) {
    cout << "caught!" << endl;
}

Derived D;

try {
    throw D;
} catch ( const Derived d) {
    throw;
} catch (const Base &b) {
    cout << "caught!" << endl;
}

Derived D;

try {
    throw D;
} catch ( const Derived &d) {
    throw;
} catch (const Base b) {
    cout << "caught!" << endl;
}

嗯,你没有展示我们预计捕获重新抛出的代码。下一个相同 try 的 catch 不应该捕获它,只有另一个 try 才能。 - Jan Hudec
3个回答

19

re-throw(重新抛出异常)不会被同一个try-catch块处理,它会一直向上抛到调用的范围。

根据[except.throw](2003 版本):

对于没有操作数的throw-expression,会重新抛出正在处理的异常。

并且:

当抛出异常时,控制权会转移到与之匹配类型的最近的处理程序(15.3); “最近”意味着线程控制最近进入try关键字后的复合语句、构造函数初始化程序或函数体并尚未退出的处理程序。

因为您的try块已经退出,所以它的处理程序不再是候选项。因此,在您的代码中没有任何catch块可以处理重新抛出的异常。

诚然,这种措辞相当令人困惑。


由于catch块位于try块之后,因此下一个catch块不符合条件。 - Jan Hudec
1
@Jan:我头疼了,但是上面的“nearest”条件不匹配吗?下一个catch是一个“handler”,其后的复合语句与其相关的try关键字尚未退出。哦,等等,它已经退出了。好的:D 我坚持我的答案中的所有内容,但感谢您帮助我理解它自己;) - Lightness Races in Orbit
修改后,我的意思是与try块相关的catch。 - user753213
@user753213:我还是不太明白你的意思。无论如何,我的回答中规定的规则是:在给定的 try { A } catch (B) { C } catch (D) { E } 中,那些 catch 块所捕获的唯一异常是在 A 中抛出的异常。在 CE 中抛出的异常是分开且独立的,这包括重新抛出的异常。 - Lightness Races in Orbit
是的,我理解的就是这样。当异常从catch处理程序重新抛出时,它必须由具有自己单独try块的catch处理程序处理。 - user753213
显示剩余4条评论

9
重新抛出的异常应该被其他 try..catch 块捕获,而不是同一 try 块的 catch 处理程序。请看以下示例:
using namespace std;
class Base
{
public:
    virtual ~Base(){}
};

class Derived : public Base
{
};

void f()
{
    try
    {
        throw Derived();
    }
    catch(Derived& ex)
    {
        cout<<"Caught in f\n";
        throw;
    }

}

int main()
{
    try
    {
        f();
    }
    catch(Base& b)
    {
        cout<<"Caught in main\n";
    }

    return 0;
}

输出结果为:

在 f 中被捕获

在 main 中被捕获


换句话说:catch 只能捕获紧跟在 try 关键字后面的代码块中尝试离开上下文的异常。 - Donal Fellows
这个例子似乎有点冗余。问题就在于这个例子。 :) - Lightness Races in Orbit

3
这应该有效:
Derived D;


try{

    try {
        throw D;
    } catch ( const Derived &d) {
        throw;
    } catch (const Base &b) {
        cout << "caught!" << endl;
    }

} catch (const Base &b) {
    cout << "caught here!" << endl;
}

就像其他人说的那样,rethrow会将相同的异常重新抛出到catch块之外。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接