章节回顾
异常处理提供了一种机制,将错误或异常情形的处理与常规控制流解耦。这使开发者能够在恰当的时间和位置灵活地处理错误,从而消除(或极大缓解)返回码所带来的混乱。
- throw语句用于抛出异常。
- try块监视其内部或所调用代码抛出的异常。
- catch块捕获匹配类型的异常并进行处理;默认情况下,被捕获的异常即视为已处理。
- 异常被立即处理:一旦抛出,控制流跳转到最近的 try块并寻找匹配的catch;若找到,则回卷栈并继续执行;若找不到,程序调用std::terminate并报告未处理异常。
- 任意数据类型(包括类)均可作为异常抛出。
- catch可指定类型捕获,亦可用省略号- ...作为通配处理器。捕获基类引用的处理器也会捕获派生类异常。
- 标准库抛出的所有异常均派生自 <exception>头文件中的std::exception;捕获std::exception&即可捕获全部标准库异常,并通过what()获取异常描述。
- 在 catch块内可抛出新异常(不会被自身捕获),亦可使用无操作数的throw;重新抛出原异常;切勿用捕获的异常变量再次抛出,否则会发生对象切片。
- 函数 try 块允许捕获整个函数体或成员初始化列表中抛出的异常,主要用于派生类构造函数。
- 绝不可在析构函数中抛出异常。
- noexcept说明符可用于声明函数的不抛/不失效保证。
- std::move_if_noexcept在对象拥有- noexcept移动构造时返回可移动右值,否则返回可复制左值,以此在强异常保证前提下优先使用移动语义,否则退回复制。
- 异常处理存在开销:通常使代码略慢,且异常触发时代价极高。异常应仅用于处理“异常”情形,而非常规错误(如输入无效)。
章节测验
编写一个 Fraction 类,其构造函数接受分子与分母。若用户传入 0 作为分母,抛出 std::runtime_error 异常(需包含头文件 <stdexcept>)。在主程序中,提示用户输入两个整数。若分数有效,输出该分数;若无效,捕获 std::exception 并提示用户分母无效。
一次示例运行:
Enter the numerator: 5
Enter the denominator: 0
Invalid denominator
