C++ 如果抛出异常并且该异常与捕获的异常类型不匹配,try-catch 语句的行为是什么?

C++ What is the behavior of a try-catch statement if an exception is thrown, and that exception does not match the type of exception caught?

我有兴趣进一步了解以下代码逻辑的行为方式:

try
{
    // might, or might not do this: throw ExceptionTypeA;
    function_which_might_throw_exception_type_a();
    
    do_A(); // do we do A?
}
catch(ExceptionTypeB)
{
    // B will never be done
    do_not_do_B();
}

// C is always done (Edit: should always be done, but actually isn't)
do_C();

简而言之,这个问题可以简单表述为:函数do_A会被调用吗?*

*[如果function_which_might_throw_exception_type_a()throw ExceptionTypeA;...当然很清楚do_A() 如果function_which_might_throw_exception_type_a() 不会抛出异常。]

上面的伪代码应该表示抛出的异常类型与 catch 子句中捕获的异常类型不同。

换句话说,虽然有一个catch子句,但这里不会捕获异常,因为它不是正确的类型。

在这种情况下,编译器生成的输出是 完全跳过 do_A() 的调用, 还是编译器生成的输出中 do_A() 被称为`?

我相当有信心,如果在try块中抛出任何异常,那么执行路径就是立即离开try块。 也就是说,我认为上面的伪代码中并没有调用do_A()。 (假设函数 function_which_might_throw_exception_type_a() 确实抛出 ExceptionTypeA。)

但是我想检查一下,因为我开始怀疑了。

仅供参考:我正在查看一段代码,更明智的做法是:

try
{
    // might, or might not do this: throw ExceptionTypeA;
    function_which_might_throw_exception_type_a();
    
    do_A(); // do we do A?

    // C **should** always be done
    do_C()
}
catch(ExceptionTypeB)
{
    // B will never be done
    do_not_do_B();
}
return something;

但是,我认为这不等同于第一个伪代码。

由于C++没有try-catch-finally类型的语句,所以不能这样表达逻辑。 (但我觉得如果可以的话会更好。)

Will the function do_A be called?

简而言之——没有。当在 try 块内抛出异常时,该块将 立即 退出。如果抛出的异常类型没有被相应的 catch 块处理,那么它将被视为在 try 块之外抛出的异常(可能 导致堆栈展开,但最终导致程序终止)。

如果您希望 do_C() 函数被调用 'always',无论抛出什么类型的异常,您都应该添加一个 catch(...)(称为“catch-all 子句”)块在你的其他特定 catch 块之后。这可以是一个空 statement/block;如果是这样,抛出的异常仍会被捕获(即不会进一步传播)但不会采取任何具体操作。

实现您想要的东西的可能方法如下:

try
{
    // might, or might not do this: throw ExceptionTypeA;
    function_which_might_throw_exception_type_a();
    
    do_A(); // If the above throws, this WILL NOT be executed
}
catch(ExceptionTypeB)
{
    // B will never be done
    do_not_do_B();
}
catch(...) {} // This will catch "ExceptionTypeA" but do nothing about it ...
do_C();       // Will 'always' execute (unless an earlier catch re-throws)
return something;