try/catch无法捕获EXCEPTION_ACCESS_VIOLATION,必须使用__try/__except配合/EHa编译选项和GetExceptionCode()判断,仅用于日志记录与安全退出,不可恢复执行。

Access Violation 不能用 try/catch 捕获
直接说结论:try/catch 对 EXCEPTION_ACCESS_VIOLATION 完全无效。它只处理 C++ 标准异常(即由 throw 主动抛出的对象),而访问违规是 CPU 触发的硬件异常,走的是 Windows 的结构化异常处理(SEH)路径。你写 try { *p = 1; } catch(...) { },p 为 nullptr 时程序照样崩,不会进 catch 块。
必须用 __try/__except 捕获 Access Violation
Windows 平台下唯一能拦截访问违规的机制是 SEH,语法为 __try + __except。关键点在于过滤表达式必须显式识别 EXCEPTION_ACCESS_VIOLATION,否则默认会继续向上搜索或终止进程:
-
__except表达式返回EXCEPTION_EXECUTE_HANDLER才进入处理块 - 必须通过
GetExceptionCode()获取当前异常码,不能只靠类型推断 - 过滤函数里调用
GetExceptionInformation()可拿到发生异常的地址、访问类型(读/写)等上下文 - VC++ 编译时需启用
/EHa(而非默认的/EHsc),否则析构函数可能不被调用,资源泄漏风险高
示例片段:
__try {
int* p = nullptr;
*p = 42; // 触发 EXCEPTION_ACCESS_VIOLATION
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
printf("捕获到内存访问违规\n");
}SEH 不等于恢复执行,更不是调试替代品
捕获到 EXCEPTION_ACCESS_VIOLATION 后,你只能做三件事:记录日志、清理关键资源、退出进程。不要尝试“修复指针后继续运行”——堆栈可能已损坏,后续行为不可预测:
Windows 命令行编码与兼容规范。涵盖 GBK/UTF-8 编码、PowerShell/pwsh 互操作、Python/Node.js、Git 配置及代码生成规则。适用于 Windows 10/11 + MSYS2/Git Bash 环境下的所有命令行操作。
立即学习“C++免费学习笔记(深入)”;
- 返回
EXCEPTION_CONTINUE_EXECUTION极其危险,仅适用于极少数可控场景(如 JIT 内存页保护切换) - SEH 无法告诉你哪一行代码越界,
arr[10]和*(int*)0xdeadbeef都报同一个异常码 - 生产环境不应依赖 SEH 拦截崩溃来“兜底”,它只是最后的保底手段;真正要靠静态分析、ASan、AppVerifier 或 WinDbg 实时调试定位根因
- 跨平台项目慎用:SEH 是 Windows 专属,Linux 下对应的是
signal(SIGSEGV, ...),两者语义和可靠性差异很大
/EHa 编译选项的隐性代价
启用 /EHa 才能让 C++ 对象析构函数在 SEH 展开时被调用,但它会让编译器对所有函数插入额外的展开表(unwind table),带来可观的二进制体积增长和轻微性能损耗:
- 即使你没写任何
__try,/EHa也会让每个函数多出几十字节的元数据 - 频繁抛 C++ 异常的代码在
/EHa下比/EHsc慢约 5–10%,因为异常分发路径变长 - 混合使用 SEH 和 C++ 异常时,
__finally块中若抛出 C++ 异常,行为未定义,MSDN 明确警告“可能跳过部分析构”
真正需要 SEH 的地方很少:比如编写反调试模块、实现自定义崩溃上报、或封装第三方闭源库(其内部触发访问违规但不暴露源码)。日常业务逻辑,请优先用智能指针、边界检查、静态断言来消灭越界源头。

















