核心要点速览

  • 异常处理三关键字:throw(抛出异常)、try(监控异常代码)、catch(捕获处理异常),核心是分离错误检测与处理
  • 基本流程:try监控→throw抛异常→catch匹配处理;无匹配则异常传播,最终未捕获则程序终止
  • 匹配规则:catch按声明顺序匹配,子类异常需在父类前捕获,catch(...)(万能捕获)必须放最后
  • 异常类型:推荐类类型(标准库异常或自定义类),可携带详细信息;避免基本类型(语义模糊)

一、三个关键字

一、throw(抛出异常)

  • 作用:检测到不可处理的错误(如参数非法)时,主动抛出异常对象,中断当前执行,通知上层处理。
  • 语法throw 表达式;(表达式结果为异常对象)。
  • 细节
    • 异常类型选择
      • 不推荐基本类型(如throw 1,语义模糊,无法区分错误类型);
      • 推荐类类型(如标准库std::invalid_argument),可携带详细信息(如"文件路径不能为空")。
    • 执行逻辑throw后,当前函数中后续代码立即终止,进入异常传播阶段(寻找匹配catch)。

二、try(监控异常)

  • 作用:包裹可能抛出异常的代码,标记需监控的区域,是异常检测的起点。
  • 语法
1
2
try { /* 可能抛异常的代码 */ }
// 必须紧跟1个及以上catch块(否则编译报错)
  • 细节
    • 不可单独存在,必须搭配catch块;
    • 无异常时,直接跳过所有catch,执行后续代码。

三、catch(捕获与处理异常)

  • 作用:匹配try块中抛出的异常类型,执行处理逻辑(如打印错误、释放资源)。
  • 语法
1
catch (异常类型 变量名) { /* 处理逻辑 */ }  // 变量名可省略
  • 规则
    1. 匹配顺序:按声明顺序匹配,首个匹配的catch执行后,后续catch不再执行。
      • 子类异常catch必须在父类前(否则父类会屏蔽子类处理)。
      • 错误示例:父类catch(std::exception&)在前,子类catch(std::out_of_range&)在后(子类处理永远不执行)。
    2. catch(...):万能捕获,兜底处理所有未匹配的异常,必须放最后(否则屏蔽后续catch)。
    3. 异常对象生命周期throw生成的临时对象存储在特殊区域,catch捕获副本或引用,处理后自动销毁。

二、执行流程

  1. 正常流程try块代码执行完毕→跳过所有catch块→执行catch之后的代码。
  2. 异常流程
    • try块中执行throw→立即终止try块,生成异常对象;
    • 按顺序检查catch块,匹配第一个兼容类型的块并执行;
    • 若未匹配,异常向上传播(到调用当前函数的外层try-catch);
    • 若全程无匹配,程序调用std::terminate()终止(默认执行abort())。

三、问答

  1. trythrowcatch的协作流程是什么?
  • try监控代码块→throw在错误时抛出异常对象,中断当前执行→按顺序匹配catch块,执行第一个匹配的处理逻辑;无匹配则异常传播,最终未捕获则程序终止。
  1. catch块的匹配顺序有什么要求?为什么?
  • 需按声明顺序匹配,且子类异常catch必须在父类前。因为父类异常可以捕获子类异常,若父类catch放前面,子类catch会被屏蔽,无法执行针对性处理。
  1. catch(...)的作用和使用注意事项?
  • 作用是捕获所有未被前面catch匹配的异常,作为兜底处理。注意必须放在所有catch块最后,否则会屏蔽后续catch,导致特定异常无法处理。
  1. 为什么推荐用类类型(而非基本类型)作为异常对象?
  • 类类型可携带详细错误信息(如what()返回的描述),支持继承多态,便于按错误类型分类处理;基本类型语义模糊,无法区分不同错误场景。