第八章 防御式编程
防御式编程的主要思想就是,子程序不应该因为传入错误数据而被破坏。其核心想法就是要承认程序都会有问题,都需要被修改。
处理外来垃圾的方法:检查所有来自外部的数据值,检查子程序的输入参数值,决定如何处理数据。
防御式编码的最佳方式就是一开始代码中引入错误,使用迭代式设计、编码前先写伪代码、写代码前先写测试用例、底层设计检查等活动都可以防止。
断言 在开发阶段使用的,让程序在运行时进行自检的代码。可以利用断言检查如下假定:
n 输入参数或输出参数的取值处于预期范围
n 子程序开始执行(结束)时,文件或流处于打开(关闭)状态
n 子程序开始执行(结束)时,文件或流的读写位置处于开头(结尾)
n 文件或流已打开
n 输入变量的值没有被子程序修改
n 指针非空
n 传入子程序的数组至少能容纳X个元素
n 表已初始化,存储着真实的数据
n 子程序开始(结束)时,容器空(满)
n 一个高度优化过的子程序与一个缓慢的子程序,结果一致
断言只在开发阶段被编译到目标代码中,而在生成代码时不编译进去。使用断言的指导建议:
n 用错误处理代码来处理预期会发生的状况,断言不行!
n 避免把需要执行的代码放入断言中(如果未编译断言呢?)
n 用断言来注解并验证前条件和后条件
n 对于高健壮性的代码,应该先用断言,再处理错误
错误处理技术:返回中立值,换用下一个正确的数据,返回与前次相同的数据,换用最接近的合法值,把警告信息记录到日志文件,返回一个错误码,调用错误处理子程序,显示出错消息,用最妥当的方式在局部处理错误,关闭程序
而处理错误最恰当的方式要根据出现错误的软件的类别而定。
异常 用异常通知程序的其它部分,发生了不可忽略的错误
n 只在真正例外的情况下才抛出异常
n 不能用异常来推卸责任
n 避免在构造函数和析构函数中抛出异常,除非你同时捕获。
n 在恰当的抽象层次抛出异常
n 在异常消息中加入导致异常的全部信息
n 避免空的catch
n 了解函数库可能抛出的异常
n 考虑创建一个集中的异常报告机制
n 把项目中对异常的使用标准化
n 考虑异常的替换方案
隔离程序,使之包容由错误产生的损害,它类似于一个消毒室。
辅助调试
n 尽早引入辅助调试的代码
n 采取进攻式编程(确保断言语句使程序终止,完全填充所有内存,完全填充所有文件或流,删除一个对向前把它填满垃圾数据)
n 计划移除调试辅助的代码(使用版本控制工具,使用内置的预处理器,编写自己的预处理器,使用调试存根)
产品代码中该保留多少防御式代码?
n 保留检查重要错误的
n 去掉检查细微错误的
n 去掉可能导致软件硬性崩溃的
n 保留可以让软件稳妥崩溃的
n 为你的技术支持人员记录错误信息的
n 确认留在代码中的错误信息都很友好
对于防御式编程,采取防御的姿态,避免过度。