异常
1. Standard Exception Classes
1)Exceptions for language support
bad_alloc
bad_cast
bad_typeid
bad_exception
2)Exceptions for the C++ standard library(logic_error)
invalid_argument
length_error
out_of_range
domain_error
3)Exceptions for errors outside the scope of a program(runtime_error)
range_error
overflow_error
underflow_error
4)ios_base::failure
2. Abrahams Guarantee
强保证(strong guarantee): 事物提交/回滚语义,从被操作的对象的角度来说, 操作失败也不会导致程序状态改变, 不会产生任何副作用。
无失败保证指根本不允许失败的发生。
重点:
1)实现强保证, 经常需要放弃一部分性能为代价。
2)如果一个函数含有多个副作用,那么其总是无法成为强异常安全的, 此时唯一的办法就是将函数分解, 以使每个分解出来的函数之副作用能被自动完成。
3)并不是所有函数都需要具有强异常安全性。
3. 对象的生命期
开始:当他的构造函数成功执行完毕并正常返回时。 (控制流抵达构造函数体的末尾时)
结束:当析构函数开始执行时。(控制流抵达析构函数的开始之处时)
4. 构造函数/析构函数抛出异常
构造失败,对象从没存在过, 他的生命期还没开始, 析构函数永远不会被调用。
C++仅仅能删除被完全构造的对象(fully contructed objects), 只有一个对象的构造函数完全运行完毕,这个对象才能被完全地构造。C++拒绝为没有完成构造操作的对象调用析构函数。
析构函数抛出异常:
我们知道禁止异常传递到析构函数外有两个原因,第一能够在异常转递的堆栈辗转开解(stack-unwinding)的过程中,防止terminate被调用。第二它能帮助确保析构函数总能完成我们希望它做的所有事情。
5. 具有强烈异常安全性的拷贝赋值的规范形式
首先,提供一个不抛出异常的swap()函数,用以交换两个对象的内容.接着,运用创建一个临时对象然后交换的手法来实现operator=
6. 尽量通过析构函数来进行一场环境下来的自动清理工作, 而不是通过try/catch
为应用程序或子系统确立一个整体的错误报告处理策略, 并且始终遵循它,并为错误报告,错误传播以及错误处理制定策略
在那些侦测到错误,自身又无法处理的地方抛出异常
在那些具有足够知识和上下文信息去处理/转换错误或强制实施边界条件的地方编写try/catch
8. 异常安全
函数应当总是支持他所能支持的最强的异常安全保证, 前提是不能给那些并不需要该保证的调用者带来额外的开销永远不要允许析构函数, 释放操作, 以及swap()函数抛出异常, 否则没法安全且可靠地进行资源清理
永远不要为函数加上异常规格,除非你想声明的是空异常规格列表, 但是这也没有必要
C++规范要求被做为异常抛出的对象必须被复制。即使被抛出的对象不会被释放,也会进行拷贝操作。这表示即使通过引用来捕获异常,也不能在catch块中修改异常对象;仅仅能修改他的拷贝。
通过引用捕获异常
一般来说,你应该用throw来重新抛出当前的异常,因为这样不会改变被传递出去的异常类型,而且更有效率,因为不用生成一个新拷贝。
一般来说,catch子句匹配异常类型时不会进行隐式类型转换。
catch子句进行异常类型匹配的顺序是它们在源代码中出现的顺序。