异常处理:异常基础与语法
核心要点速览
- 异常处理三关键字:
throw(抛出异常)、try(监控异常代码)、catch(捕获处理异常),核心是分离错误检测与处理 - 基本流程:
try监控→throw抛异常→catch匹配处理;无匹配则异常传播,最终未捕获则程序终止 - 匹配规则:
catch按声明顺序匹配,子类异常需在父类前捕获,catch(...)(万能捕获)必须放最后 - 异常类型:推荐类类型(标准库异常或自定义类),可携带详细信息;避免基本类型(语义模糊)
一、三个关键字
一、throw(抛出异常)
- 作用:检测到不可处理的错误(如参数非法)时,主动抛出异常对象,中断当前执行,通知上层处理。
- 语法:
throw 表达式;(表达式结果为异常对象)。 - 细节:
- 异常类型选择:
- 不推荐基本类型(如
throw 1,语义模糊,无法区分错误类型); - 推荐类类型(如标准库
std::invalid_argument),可携带详细信息(如"文件路径不能为空")。
- 不推荐基本类型(如
- 执行逻辑:
throw后,当前函数中后续代码立即终止,进入异常传播阶段(寻找匹配catch)。
- 异常类型选择:
二、try(监控异常)
- 作用:包裹可能抛出异常的代码,标记需监控的区域,是异常检测的起点。
- 语法:
1 | try { /* 可能抛异常的代码 */ } |
- 细节:
- 不可单独存在,必须搭配
catch块; - 无异常时,直接跳过所有
catch,执行后续代码。
- 不可单独存在,必须搭配
三、catch(捕获与处理异常)
- 作用:匹配
try块中抛出的异常类型,执行处理逻辑(如打印错误、释放资源)。 - 语法:
1 | catch (异常类型 变量名) { /* 处理逻辑 */ } // 变量名可省略 |
- 规则:
- 匹配顺序:按声明顺序匹配,首个匹配的
catch执行后,后续catch不再执行。- 子类异常
catch必须在父类前(否则父类会屏蔽子类处理)。 - 错误示例:父类
catch(std::exception&)在前,子类catch(std::out_of_range&)在后(子类处理永远不执行)。
- 子类异常
catch(...):万能捕获,兜底处理所有未匹配的异常,必须放最后(否则屏蔽后续catch)。- 异常对象生命周期:
throw生成的临时对象存储在特殊区域,catch捕获副本或引用,处理后自动销毁。
- 匹配顺序:按声明顺序匹配,首个匹配的
二、执行流程
- 正常流程:
try块代码执行完毕→跳过所有catch块→执行catch之后的代码。 - 异常流程:
try块中执行throw→立即终止try块,生成异常对象;- 按顺序检查
catch块,匹配第一个兼容类型的块并执行; - 若未匹配,异常向上传播(到调用当前函数的外层
try-catch); - 若全程无匹配,程序调用
std::terminate()终止(默认执行abort())。
三、问答
try、throw、catch的协作流程是什么?
try监控代码块→throw在错误时抛出异常对象,中断当前执行→按顺序匹配catch块,执行第一个匹配的处理逻辑;无匹配则异常传播,最终未捕获则程序终止。
catch块的匹配顺序有什么要求?为什么?
- 需按声明顺序匹配,且子类异常
catch必须在父类前。因为父类异常可以捕获子类异常,若父类catch放前面,子类catch会被屏蔽,无法执行针对性处理。
catch(...)的作用和使用注意事项?
- 作用是捕获所有未被前面
catch匹配的异常,作为兜底处理。注意必须放在所有catch块最后,否则会屏蔽后续catch,导致特定异常无法处理。
- 为什么推荐用类类型(而非基本类型)作为异常对象?
- 类类型可携带详细错误信息(如
what()返回的描述),支持继承多态,便于按错误类型分类处理;基本类型语义模糊,无法区分不同错误场景。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 肖恩的博客!
评论

