现在的位置: 首页 > 综合 > 正文

异常

2012年11月05日 ⁄ 综合 ⁄ 共 1625字 ⁄ 字号 评论关闭
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

基本保证(basic guarantee): 失败的操作可能会改变程序的状态, 但是不会发生任何泄露, 受失败的操作影响的对象/模块仍然可用,可析构,并处于一致的状态下(不过该状态并不一定是可预测的)。
强保证(strong guarantee): 事物提交/回滚语义,从被操作的对象的角度来说, 操作失败也不会导致程序状态改变, 不会产生任何副作用。
无失败保证指根本不允许失败的发生。
重点:
1)实现强保证, 经常需要放弃一部分性能为代价。
2)如果一个函数含有多个副作用,那么其总是无法成为强异常安全的, 此时唯一的办法就是将函数分解, 以使每个分解出来的函数之副作用能被自动完成。
3)并不是所有函数都需要具有强异常安全性。
3. 对象的生命期
开始:当他的构造函数成功执行完毕并正常返回时。 (控制流抵达构造函数体的末尾时)
结束:当析构函数开始执行时。(控制流抵达析构函数的开始之处时)

4. 构造函数/析构函数抛出异常

构造函数抛出异常:
构造失败,对象从没存在过, 他的生命期还没开始, 析构函数永远不会被调用。
C++仅仅能删除被完全构造的对象(fully contructed objects), 只有一个对象的构造函数完全运行完毕,这个对象才能被完全地构造。C++拒绝为没有完成构造操作的对象调用析构函数。
析构函数抛出异常:
我们知道禁止异常传递到析构函数外有两个原因,第一能够在异常转递的堆栈辗转开解(stack-unwinding)的过程中,防止terminate被调用。第二它能帮助确保析构函数总能完成我们希望它做的所有事情。

5. 具有强烈异常安全性的拷贝赋值的规范形式

首先,提供一个不抛出异常的swap()函数,用以交换两个对象的内容.
接着,运用创建一个临时对象然后交换的手法来实现operator=

6. 尽量通过析构函数来进行一场环境下来的自动清理工作, 而不是通过try/catch


7. 异常处理原则

为应用程序或子系统确立一个整体的错误报告处理策略, 并且始终遵循它,并为错误报告,错误传播以及错误处理制定策略
在那些侦测到错误,自身又无法处理的地方抛出异常
在那些具有足够知识和上下文信息去处理/转换错误或强制实施边界条件的地方编写try/catch

8. 异常安全

函数应当总是支持他所能支持的最强的异常安全保证, 前提是不能给那些并不需要该保证的调用者带来额外的开销

永远不要允许析构函数, 释放操作, 以及swap()函数抛出异常, 否则没法安全且可靠地进行资源清理

9. 异常规格

永远不要为函数加上异常规格,除非你想声明的是空异常规格列表, 但是这也没有必要

10. 异常workflow
C++规范要求被做为异常抛出的对象必须被复制。即使被抛出的对象不会被释放,也会进行拷贝操作。这表示即使通过引用来捕获异常,也不能在catch块中修改异常对象;仅仅能修改他的拷贝。
通过引用捕获异常 
一般来说,你应该用throw来重新抛出当前的异常,因为这样不会改变被传递出去的异常类型,而且更有效率,因为不用生成一个新拷贝。 
一般来说,catch子句匹配异常类型时不会进行隐式类型转换。 
catch子句进行异常类型匹配的顺序是它们在源代码中出现的顺序。

抱歉!评论已关闭.