能,但仅限于当前 try 块中抛出的、未被前面 catch 子句捕获的异常;不捕获信号、setjmp/longjmp 跳转或未定义行为导致的崩溃;必须置于 catch 列表末尾,否则编译报错。

catch(...) 能捕获所有异常吗?
能,但仅限于当前 try 块中抛出的、未被前面 catch 子句捕获的异常。它不捕获信号(如 SIGSEGV)、C 风格的 setjmp/longjmp 跳转,也不处理未定义行为导致的崩溃(比如野指针访问后程序直接终止,根本没机会进 catch(...))。
它本质是“兜底”,不是“万能急救包”。常见误用是把它放在主函数末尾就以为能防止程序崩溃——实际无效。
catch(...) 必须放在 catch 列表最后
否则编译报错:error: '...' handler must be the last handler for its try block。C++ 标准强制要求它只能作为最后一个 catch 分支。
正确顺序示例:
立即学习“C++免费学习笔记(深入)”;
try {
risky_function();
} catch (const std::exception& e) {
std::cerr << "std exception: " << e.what() << "\n";
} catch (int n) {
std::cerr << "int exception: " << n << "\n";
} catch (...) {
std::cerr << "unknown exception caught\n";
}
- 前面的
catch按顺序匹配,一旦匹配成功,后续分支(包括catch(...))不再执行 - 如果只写
catch(...)而不写其他catch,它确实能捕获所有 C++ 异常,但你完全丢失了异常类型和内容信息
catch(...) 里无法获取异常对象信息
这是最常被忽略的限制:你只知道“有异常”,但不知道“是什么异常”“为什么抛出”。... 不提供变量名,也不能用 typeid 或 dynamic_cast 反查类型。
所以实用做法通常是:
- 在
catch(...)内记录日志(如时间、调用栈地址、线程 ID),方便事后分析 - 配合编译器扩展(如 GCC 的
__cxa_current_exception_type())做类型探测——但高度非标准、不可移植 - 更稳妥的方式是:优先用
catch (const std::exception&)捕获标准异常,再用catch(...)做最后保险,并立即调用std::terminate()或记录后throw继续上抛(如果上下文允许)
与 noexcept 和异常规范的交互
如果函数声明为 noexcept(或隐式 noexcept(true)),而内部却抛出了异常且未被该函数内的 try/catch 捕获,程序会直接调用 std::terminate() ——此时外部的 catch(...) 完全没机会运行。
这意味着:
-
catch(...)对noexcept函数内未处理的异常无效 - 若你依赖
catch(...)做错误兜底,请确保关键函数没加noexcept,或自己在函数体内做完整捕获 - 第三方库函数若标了
noexcept,又意外抛异常(比如违反前提条件),你的外层catch(...)也救不了
真正难处理的从来不是语法怎么写,而是异常从哪来、能不能传到你写的 catch(...) 里——堆栈是否被破坏、是否跨 DLL 边界、是否混用不同 CRT 版本,这些都可能让 catch(...) 彻底静默失效。









