✅ 一、异常处理基本语法(try-catch)
try {
// 可能抛出异常的代码
} catch (const std::exception& e) {
// 捕获异常
} catch (...) {
// 捕获所有类型的异常
}
✅ 二、throw 的用法
抛出异常对象,一般是值(可为内置类型、类对象)--->也就是后面跟着类、对象、值都可以
throw std::runtime_error("error");
throw 1; // 抛出 int 类型异常
throw MyError(); // 抛出用户自定义类
可重新抛出当前异常:
catch (...) {
// 做点处理
throw; // 重新抛出
}
✅ 三、异常匹配规则(按顺序匹配)
会按 catch **顺序查找**最先匹配类型 catch by value 会导致 slicing(对象切片),推荐使用 catch by reference
面试常问点总结(口诀式记忆)“三块一安全”
✔ 三块结构(try-catch-throw)
-
try 块
用于包裹可能抛出异常的代码段。必须紧跟至少一个 catch,否则编译错误。 -
throw 语句
在某些条件下显式抛出异常。可以抛出任何类型的对象(内置类型、自定义类等)。 -
catch 块
捕获异常对象,进行处理,防止程序崩溃。按类型顺序匹配,第一个匹配的执行。
(🚨 注意:必须捕获引用类型,防止切片)
✔ 一机制(栈展开 + 析构)
当异常抛出但未被当前函数捕获时,会发生栈展开
-
栈展开(Stack Unwinding)
异常沿着调用链回溯查找匹配的 catch。每经过一层函数返回,当前作用域的局部对象都会被自动销毁(即调用其析构函数)。 -
自动调用析构函数(即 RAII 的基础)
栈展开过程中,所有已构造完成的局部对象都会被正确析构。保证不会发生资源泄漏(前提是资源绑定在对象上)。
✔ 安全原则(RAII + 不在析构抛异常)
异常机制要想安全可靠,必须遵循以下两大原则:
-
RAII(Resource Acquisition Is Initialization)
用对象的生命周期管理资源,构造函数获取资源、析构函数释放资源。
避免手动 new/delete、malloc/free。
遇到异常时,不依赖显式清理逻辑,栈展开自动处理。 -
析构函数中不能抛异常
若栈展开期间析构函数再抛出异常,会导致程序调用 std::terminate() 强制终止。
所以 C++11 开始,析构函数必须被声明为 noexcept。
编译时错误
🔚 总结:C++ 异常相关编译时错误常见来源
| 类型 | 示例 | 会报错? |
|---|---|---|
| 语法错误 | 缺失 catch、括号错误 | ✅ |
| 抛出不完整类型 | throw Incomplete(); |
✅ |
| 函数异常规范冲突 | noexcept 函数抛异常 |
✅(逻辑或运行时) |
| 对象构造失败 | 异常对象构造器再抛异常 | ✅(运行时崩溃) |
| 访问权限错误 | 捕获后访问私有成员 | ✅ |
| 类型不匹配 | catch 捕获错误类型 |
✅/❌(未匹配到会 terminate) |
口诀:抛拷问权限,捕错需括号;析构慎 throw,异常需头包;noexcept守信,匹配要周到。
浙公网安备 33010602011771号