More Effective C++:3、异常

C++新增的异常 (exception) 机制改变了某些事情,这种改变是深刻的,彻底的,可能是令人不舒服的。例如:使用未经处理的或原始的指针变得很危险;资源泄漏的可能性增加了;写出具有你希望的行为的构造函数与析构函数变得更加困难。特别小心防止程序执行时突然崩溃。执行程序和库程序尺寸增加了,同时运行速度降低了。


这就使我们所知道的事情。很多使用 C++ 的人都不知道在程序中使用异常,大多数人不知道如何正确使用它。在异常被抛出后,使软件的行为具有可预测性和可靠性,在众多方法中至今也没有一一个-致的方法能做到这点。(为了深刻了解这个问题,参见Tom Cargill 写的 Exception Handling: A False Sense of Security。有关这些问题的进展情况的信息,参见 Jack Reeves 写的 Coping with Exceptions 和Herb Sutter 写的 Except ion- Safe Generic Containers。)


我们知道:程序能够在存在异常的情况下正常运行是因为它们按照要求进行了设计,而不是因为巧合。异常安全 (Exception-safe) 的程序不是偶然建立的。一个没有按照要求进行设计的程序在存在异常的情况下运行正常的概率与一个没有按照多线程要求进行设计的程序在多线程的环境下运行正常的概率相同,概率为 0。


为什么使用异常呢?自从 C 语言被发明初来,C 程序员就满足于使用错误代码 (Errorcode),所以为什么还要弄来异常呢,特别是如果异常如我上面所说的那样存在着问题。答案是简单的:异常不能被忽略。如果一个函数通过设置一个状态变量或返回错误代码来表示一个异常状态,没有办法保证函数调用者将一定检测变量或测试错误代码。结果程序会从它遇到的异常状态继续运行,异常没有被捕获,程序立即会终止执行。


C 程序员能够仅通过 setjmp 和 longjmp 来完成与异常处理相似的功能。但是当 longjmp 在C++ 中使用时,它存在一些缺陷,当它调整堆栈时不能对局部对象调用析构函数。( WQ 加注,VC++ 能保证这一点, 但不要依赖这一点。) 而大多数 C++ 程序员依赖于这些析构函数的调用,所以 setjmp 和 longjmp 不能够替换异常处理。如果你需要一个方法,能够通知不可被忽略的异常状态,并且搜索栈空间 (searching the stack) 以便找到异常处理代码时,你还得确保局部对象的析构函数必须被调用,这时你就需要使用C++的异常处理。


因为我们已经对使用异常处理的程序设计有了很多了解,下面这些条款仅是一个对于写出异常安全 (Exception-safe) 软件的不完整的指导。然而它们给任何在 C++ 中使用异常处理的人介绍了一些重要思想。通过留意下面这些指导,你能够提高自己软件的正确性,强壮性和高效性,并且你将回避开许多在使用异常处理时经常遇到的问题。



条款9:利用 destructors 避免资源泄漏



条款10:在 constructors 内阻止资源泄漏(resource leak)



条款11:禁止异常(exceptions)流出 destructors 之外



条款12:了解 “抛出一个 exception” 与 “传递一个参数” 或 “调用一个虚函数” 之间的差异



条款13:以 by reference 方式捕获 exceptions



条款14:明智运用 exception specifications



条款15:了解异常处理(exception handling)的成本

你可能感兴趣的:(C++,基础构建,More,Effective,C++)