异常处理技术疑问:catch块是否仅执行?多catch块遇二次异常如何捕获?
关于C++ Catch块的两个常见问题解答
嘿,咱们逐个来理清这两个问题:
1. Catch块是否仅会在异常发生时执行?
没错,catch块只有当它对应的try块抛出了与自身异常类型匹配的异常,且这个异常没有被更内层的catch捕获时,才会被执行。如果try块里没有抛出任何异常,或者抛出的异常类型和当前catch块的签名不匹配,那这个catch块就会直接被跳过,完全不会执行。
举个简单的例子就能明白:
#include <iostream> #include <stdexcept> int main() { try { std::cout << "我在try块里,没抛异常~" << std::endl; } catch (const std::runtime_error& e) { // 这个catch块根本不会运行,因为try里没抛匹配的异常 std::cerr << "捕获到异常:" << e.what() << std::endl; } try { throw std::logic_error("抛出一个逻辑异常"); } catch (const std::runtime_error& e) { // 类型不匹配,这个catch也不会执行 std::cerr << "捕获到运行时异常:" << e.what() << std::endl; } catch (const std::exception& e) { // 这个catch会执行,因为logic_error继承自exception,类型匹配 std::cerr << "捕获到异常:" << e.what() << std::endl; } return 0; }
2. 栈展开过程中抛出第二个异常,catch块会捕获哪些?
这个情况要特别注意:当第一个异常抛出后,程序会进入栈展开阶段——也就是沿着调用栈往上走,依次销毁当前栈帧里的局部对象,同时寻找能匹配第一个异常的catch块。如果在这个栈展开的过程中(比如某个局部对象的析构函数里抛出了第二个异常),而第一个异常还没被任何catch块处理,那根据C++标准,程序会直接调用std::terminate()终止运行,不会有任何catch块去捕获第二个异常,第一个异常也得不到处理。
看这个反面例子:
#include <iostream> #include <stdexcept> class TroubleMaker { public: ~TroubleMaker() { // 栈展开时析构这个对象,抛出第二个异常 throw std::runtime_error("析构函数里的异常"); } }; void innerFunc() { TroubleMaker obj; // 抛出第一个异常 throw std::logic_error("第一个异常"); } int main() { try { innerFunc(); } catch (const std::exception& e) { // 这个catch块永远不会被执行! std::cerr << "捕获到异常:" << e.what() << std::endl; } return 0; }
运行这段代码,你会发现程序直接崩溃,不会进入任何catch块——因为栈展开时析构函数抛出的第二个异常,触发了std::terminate()。
不过有个例外:如果第一个异常已经被某个catch块成功捕获了,之后在处理这个异常的过程中(比如catch块内部)又抛出第二个异常,那第二个异常可以被外层的try-catch结构捕获(如果有的话),但这已经不属于栈展开阶段的情况了。
内容的提问来源于stack exchange,提问作者Allanqunzi
相关产品推荐
相关产品推荐

