C++的try/catch仅捕获显式throw抛出的异常,无法处理空指针解引用、除零等信号或未定义行为;catch(...)也不能捕获这些,需用sigaction或SetUnhandledExceptionFilter等平台机制。

直接说结论:C++ 的 try/catch 不是“开关式”异常处理工具,它只捕获被 throw 显式抛出的异常,对空指针解引用、数组越界、除零等底层错误默认不生效——这些属于信号(signal)或未定义行为,catch(...) 也抓不到。
哪些异常能被 try/catch 捕获
只有从 throw 表达式主动抛出的对象才能进入 catch 流程。常见合法抛出包括:
-
throw std::runtime_error("msg")、throw 42、throw std::string("oops") -
标准库函数(如
std::vector::at()、std::stoi())在检查失败时内部调用throw - 你自己写的函数中显式
throw,且调用链未被noexcept阻断
注意:throw 抛出的类型必须能被某个 catch 子句匹配(类型兼容或可隐式转换),否则会调用 std::terminate() 终止程序。
catch(...) 真的能兜住一切吗
不能。它只能捕获 C++ 异常对象,对以下情况完全无效:
立即学习“C++免费学习笔记(深入)”;
- Linux 下的
SIGSEGV(段错误)、SIGFPE(浮点异常)等信号 - Windows 下的
ACCESS_VIOLATION、INTERRUPT - 未初始化指针解引用、野指针、栈溢出、
delete已释放内存等未定义行为
如果真想拦截这类错误,得用平台相关机制:sigaction()(Linux)、SetUnhandledExceptionFilter()(Windows),但它们和 try/catch 属于不同机制,不能混用。
为什么 catch 块里别写太重的逻辑
异常处理期间栈正在展开(stack unwinding),此时若在 catch 中抛出新异常且未被处理,程序直接终止。更隐蔽的风险是:
- 在
catch中调用可能抛异常的函数(比如std::string构造、new内存分配) - 在
catch中调用未声明noexcept的析构函数(尤其当该析构函数又抛异常) - 试图在
catch中恢复执行流到异常点(C++ 不支持“继续执行”)
稳妥做法是:在 catch 中只做日志、资源清理(确保不抛异常)、或转为错误码/状态返回;复杂恢复逻辑应放在上层调用者中判断后执行。
常见误用与编译器差异
不同编译器对异常支持有实际影响:
- Clang/GCC 默认启用异常(
-fexceptions),但若加了-fno-exceptions,所有try/catch/throw会被禁用,编译报错 - MSVC 在 `/EHsc` 模式下才支持 C++ 异常;`/EHs-` 会禁用异常处理,
throw变成未定义行为 - 嵌入式或性能敏感场景常全局禁用异常,此时必须用返回码、
std::optional或std::expected(C++23)替代
一个容易忽略的细节:catch 按顺序匹配,基类 catch 必须放在派生类之后,否则派生类分支永远无法到达——这不是语法错误,而是逻辑失效。











