C++异常处理机制通过throw、try和catch实现:throw抛出异常并终止当前执行流,try块保护可能出错的代码,catch按顺序匹配并处理对应类型异常;未捕获的异常触发栈展开,最终调用std::terminate终止程序。

set_terminate 函数必须配合 throw 使用才生效
直接在 main 外抛异常(比如全局对象构造函数里 throw)不会触发 std::set_terminate,除非该异常未被任何 catch 捕获。C++ 标准规定:只有当异常传播到 main 之外仍无人处理时,才会调用当前的 terminate handler。
常见误操作是只注册 handler 却没真正让异常逃逸出去:
- 忘记在
main中不捕获、或显式throw一个未处理异常 - 在全局对象构造中
throw,但链接器把初始化顺序搞乱,导致异常发生在 handler 注册前(此时走默认 terminate) - 用了
noexcept函数抛异常,会直接调用std::terminate,但绕过自定义 handler(除非你重置了它)
如何可靠注册并测试全局异常终止处理器
必须在程序早期(最好 main 第一行)调用 std::set_terminate,且 handler 函数签名严格为 void():
void my_terminate() {
std::cerr << "Global uncaught exception!\n";
// 可以写日志、生成 core dump、调用 abort()
std::abort();
}
int main() {
std::set_terminate(my_terminate);
throw std::runtime_error("test");
}注意点:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- handler 不能抛异常,否则二次调用
terminate,行为未定义 - 不要在 handler 里调用
std::exit或返回——terminate的语义是“程序必须终止”,返回即违反契约 - 多线程下,
set_terminate是进程级设置,所有线程共用同一个 handler
Windows 上 Structured Exception (SEH) 不受 set_terminate 控制
set_terminate 只管 C++ 异常(throw 抛出的),对访问违规、除零等系统级异常完全无效。Windows 下需额外用 SetUnhandledExceptionFilter 或 __try/__except 捕获 SEH:
LONG WINAPI SehHandler(EXCEPTION_POINTERS* p) {
// 处理 AV、INT_DIVIDE_BY_ZERO 等
return EXCEPTION_EXECUTE_HANDLER;
}
int main() {
SetUnhandledExceptionFilter(SehHandler);
std::set_terminate(my_terminate);
*(int*)0 = 1; // 触发 SEH,不是 C++ 异常
}关键区别:
- C++ 异常可被
catch捕获;SEH 在 Windows 层面,C++ 的catch(...)默认抓不到 - Linux 下对应的是
signal(SIGSEGV, ...),同样独立于set_terminate - 跨平台统一兜底?得分别处理 C++ 异常 + 平台特定信号/SEH
为什么 try-catch(...) 在 main 里不能替代 set_terminate
try { ... } catch(...) { ... } 只能捕获从 try 块内抛出、且未在内部被拦截的异常;它对以下情况完全无能为力:
- 全局对象构造/析构期间抛出的异常(
main尚未开始或已结束) - 从
std::thread启动的函数里抛出、且未调用std::current_exception转移的异常 - 调用
std::abort、std::exit、或发生栈溢出等非异常终止
也就是说:set_terminate 是最后一道防线,catch(...) 是常规防御层——两者定位不同,不可互相取代。
最易被忽略的一点:全局异常处理器无法恢复执行,它的唯一合法动作是记录、诊断、然后终止。试图在里面 longjmp 或 setjmp 跳转,属于未定义行为。

















