C++ 异常处理:try-catch 与 throw
传统错误处理依赖函数返回值与全局状态码判断,代码容易陷入深层嵌套且难以统一接管。异常处理机制将正常业务逻辑与错误恢复代码物理隔离,让程序在遇到不可恢复状态时自动中断当前执行流,精准跳转至预设处理分支。
- 引入 必要标准库:在源文件头部添加
#include <exception>与#include <string>。前者提供基础异常类定义,后者支持错误字符串的安全传递与解析。 - 包裹 风险执行区:使用
try关键字后接花括号{},将可能引发运行时中断的逻辑(如文件读写、网络请求、动态数组访问)完整移入块内。编译器会在此区域隐式植入状态检查点。 - 植入 条件判断语句:在
try块内部编写 校验逻辑。当业务数据或环境状态不满足安全要求时,立即触发错误分支,阻止破坏性操作继续向底层蔓延。 - 抛出 错误载体:调用
throw关键字后接一个具体数据对象。该对象作为错误信号被压入临时存储区。传递 基础类型(如int状态码)或标准库异常对象(如std::runtime_error)。 - 部署 类型拦截器:在
try块闭合花括号正下方排列catch块。圆括号()内声明参数类型与变量名。当throw被激活,运行时环境会遍历 下方所有catch,寻找类型完全匹配或可隐式转换的声明。 - 执行 恢复逻辑:在匹配的
catch大括号内编写 补偿操作。记录 错误上下文日志,释放 临时占用资源,返回 降级后的安全默认值,或重新抛出 给上层调用栈处理。
完整编码结构示例如下:
#include <iostream>
#include <stdexcept>
int calculate_division(int dividend, int divisor) {
if (divisor == 0) {
throw std::invalid_argument("除数不允许为零");
}
return dividend / divisor;
}
int main() {
int result = 0;
try {
result = calculate_division(10, 0);
std::cout << "计算结果:" << result << std::endl;
}
catch (const std::invalid_argument& err) {
std::cout << "拦截参数错误:" << err.what() << std::endl;
result = 0;
}
catch (...) {
std::cout << "拦截未知运行时故障" << std::endl;
result = -1;
}
return 0;
}
| 捕获声明方式 | 匹配规则 | 适用场景 | 性能与内存开销 |
|---|---|---|---|
catch (std::exception e) |
按值拷贝匹配 | 仅读取错误信息且无需修改内部状态 | 产生对象副本,开销略高 |
catch (const std::exception& e) |
引用绑定匹配 | 标准业务错误接管(推荐写法) | 零拷贝,性能最优 |
catch (std::exception* e) |
指针地址匹配 | 堆分配异常的精细管理 | 需手动调用 delete 防泄漏 |
catch (...) |
通配符匹配 | 兜底拦截未预见错误 | 开销极低,仅获取控制权 |
- 剥离 析构函数中的异常代码:C++ 对象生命周期结束时会调用析构函数。若析构过程中再次抛出 异常,且原调用栈已存在未处理异常,运行时将直接调用
std::terminate强制终止进程。将资源释放失败的情况转为 内部日志写入或状态标记,绝不向外抛出信号。 - 替换 动态内存为智能指针:异常触发瞬间,系统会执行栈展开操作,自动调用当前栈帧所有局部对象的析构函数。若使用裸指针管理堆内存,指针变量销毁但指向的内存不会被释放。将
new分配替换 为std::make_unique或std::make_shared,利用智能指针的析构契约确保内存绝对安全回收。 - 统一 自定义错误继承链:所有业务专属异常类必须公开继承
std::exception。重写what()虚函数并返回固定错误描述字符串。外部调用方只需捕获std::exception基类引用,即可通过多态机制直接读取what()内容,避免编写冗长的类型分支判断。 - 收敛 异常穿透作用域:跨动态链接库(DLL/so)边界抛出异常可能导致二进制接口不兼容与内存分配器错乱。在模块对外导出接口处增加 转换层,将内部异常捕获 后转为标准错误码或
HRESULT结构体返回,阻断异常跨越编译边界。

暂无评论,快来抢沙发吧!