异常
异常处理提供了一种将控制和信息从程序执行过程中的某个点转移到之前执行过程经过的某个点相关的处理程序的方法(换句话说,异常处理将控制转移到调用堆栈向上)。
求值一个 throw 表达式 将抛出一个异常。异常也可以在 其他上下文 中抛出。
为了捕获异常,throw 表达式必须在 try 块 中,并且 try 块必须包含一个与异常对象类型匹配的 处理程序。
在声明函数时,可以提供以下规范来限制函数可能抛出的异常类型
(直到 C++17) |
(自 C++11 起) |
异常处理期间发生的错误由 std::terminate 和 std::unexpected(直到 C++17) 处理。
内容 |
[编辑] 用法
虽然 throw 表达式可以用于将控制转移到执行堆栈上任意代码块,用于任意原因(类似于 std::longjmp),但其预期用途是错误处理。
[编辑] 错误处理
抛出异常用于从函数中发出错误信号,其中“错误”通常仅限于以下内容[1][2][3]
- 无法满足后置条件,例如无法生成有效的返回值对象。
- 无法满足必须调用的另一个函数的先决条件。
- (对于非私有成员函数)无法(重新)建立类不变量。
特别是,这意味着构造函数(另见 RAII)和大多数运算符的失败应通过抛出异常来报告。
此外,所谓的宽松契约函数使用异常来指示不可接受的输入,例如,std::basic_string::at 没有先决条件,但会抛出异常来指示索引越界。
[编辑] 异常安全性
在函数报告错误条件后,可能会针对程序状态提供额外的保证。通常识别以下四级异常保证[4][5][6],它们彼此构成严格的超集
- 无抛出(或无故障)异常保证 — 函数从不抛出异常。无抛出(错误通过其他方式报告或隐藏)是 析构函数 和可能在堆栈展开期间调用的其他函数的预期。 默认情况下,析构函数 是
noexcept
的。(自 C++11 起)无故障(函数始终成功)是交换、移动构造函数 和其他由提供强异常保证的函数使用的函数的预期。 - 强异常保证 — 如果函数抛出异常,则程序的状态将回滚到函数调用之前的状态(例如,std::vector::push_back)。
- 基本异常保证 — 如果函数抛出异常,则程序处于有效状态。不会泄漏资源,并且所有对象的非变量都保持完整。
- 无异常保证 — 如果函数抛出异常,则程序可能处于无效状态:可能发生资源泄漏、内存损坏或其他破坏非变量的错误。
通用组件可能还会提供异常中立保证:如果从模板参数抛出异常(例如,从std::sort的Compare
函数对象或从std::make_shared中T
的构造函数抛出),则该异常将以不变的方式传播给调用者。
[edit] 异常对象
虽然任何完整类型的对象和指向void的cv指针都可以作为异常对象抛出,但所有标准库函数都按值抛出无名对象,并且这些对象的类型是从std::exception(直接或间接)派生的。 用户定义的异常通常遵循此模式。[7][8][9]
为了避免不必要的异常对象复制和对象切片,处理程序的最佳实践是通过引用捕获。[10][11][12][13]
[edit] 外部链接
|