发布于2026-07-19 阅读(0)
扫一扫,手机访问
先抛出一个结论:能用 try-catch 捕获的,只有真正被 throw 抛出的 C++ 异常。 像空指针解引用、除零这类系统级错误,默认是不会触发 catch 的,除非编译器开启特定异常机制(比如 Windows 的 SEH 转换)。
看这张图,直观展示了 C++ 异常处理的边界:
很多人以为 catch(...) 能抓一切,真相远没那么简单。它只捕获 C++ 异常对象,对下面这些情况完全无感:
nullptr 导致的段错误(SIGSEGV),在 Linux/macOS 下直接进程终止,catch 根本来不及反应int x = 1 / 0; —— 这是 CPU 级别的 trap,C++ 标准压根不把它定义为异常new 失败时,只有开了 nothrow 才会抛 std::bad_alloc)验证方法很简单:写个 throw 42; 能被捕获;但 *(int*)0 = 1; 会直接 crash,catch(...) 连运行的机会都没有。
必须匹配,但规则比表面严格。不是“能转就行”,而是要求类型相同、公有继承、或有可调用的拷贝/移动构造函数:
throw std::runtime_error("msg"); → 可被 catch(std::exception& e) 捕获(公有继承)throw "hello"; → 只能被 catch(const char*) 捕获,catch(std::string) 不行(隐式转换不参与匹配)throw 3.14; → catch(int) 捕不到,catch(double) 才行核心建议:始终抛 std::exception 派生类,避免基础类型传递导致的切片或生命周期问题。
值传递会触发异常对象拷贝,可能抛新异常(比如拷贝构造函数里 new 失败),导致栈展开中断、程序终止。看这个例子:
class BadCopy {public: BadCopy() = default; BadCopy(const BadCopy&) { throw std::runtime_error("copy failed"); }};// ...try { throw BadCopy{};} catch(BadCopy b) { /* 这里会二次崩溃 */ }正确写法只有一种:
catch(const std::exception& e) —— 安全、高效、支持多态catch(std::exception e)(值传递)和 catch(std::exception&& e)(仅匹配右值,漏掉大部分情况)构造函数中途 throw,已构造的成员会自动析构,但裸指针、文件描述符等不会。看个错例:
FILE* fp = fopen("x.txt", "r"); if (!fp) throw std::runtime_error("open fail"); —— fopen 成功后若后续 throw,fp 泄漏std::unique_ptr 或 std::ifstream记住:C++ 异常安全的唯一可靠路径是 RAII,不是靠 try-catch 到处兜底。
话题回到最容易忽略的一点:noexcept 函数里如果意外抛出异常,程序会立刻调用 std::terminate,连 catch(...) 都来不及触发。检查第三方库接口是否标记 noexcept,比写 try 更关键。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8