要点记录:契约式设计
第23条 契约式设计
第24条 死掉的程序不会说谎
第25条 断言式编程
参考之前关于 C++ 程序设计的总结 我对 OOD 中封装性和抽象的思考
防御式编程 defensive programming 和 契约式编程(或契约式设计)contract programming, design by contract (DbC) 曾在《代码大全》第2版中论述过。契约式编程是防御式编程的递进。
高抽象编程语言(函数式)的契约式编程,其中的 precondition 前置条件、postcondition 后置条件、invariant 不变式,可以用语言内建机制实现。而传统的命令式语言,可能需要把这些抽象成独立的代码或函数,施加在功能代码前后。
规范化的前置/后置条件、不变式,可以看成是对代码功能(函数、类)的说明和文档化。检查代码是否不多不少刚好完成它所宣称的功能。
一般,程序尽早崩溃,要比潜藏问题带着缺陷运行的损害小。不可知或未定义状态是最糟糕的。尽早指,可以提前到程序的启动或初始化阶段、调试测试阶段,或者编译阶段不通过。
利用断言可以发现不可能的假设出现,要么是假设本身不合理,要么是调用流程不合规。断言可作为指定代码功能契约的一种方式。静态断言可将崩溃提前至编译期,运行时断言可将崩溃提前至调试期。
assert 函数惯用法:
标注控制流不可能到达这里,一般用在分支结构中,如 if 的末尾 else, switch 的末尾 default:
assert(!"cannot hit here");
断言失败时,输出描述性文本。有些库本身内建这种 assert,如 MSVCRT 的 _ASSERTE 宏。这里使用逻辑与的 conditional and 特性完成这个功能:
assert(expr && "assert description");
不要让断言产生副作用。assert(expr) 中的 expr 不能是影响程序控制流和正确性的语句,也即关闭断言时,程序的行为应该和打开断言相同。
在 release 版中也打开断言。
一般,断言在 release 版中会关闭。为了能在 release 版中检查出关键前置条件失败(假设条件失败),也可以打开断言,并显示及保存出错时的现场信息,以便用户可以反馈给维护者。这实际上是一种 bug reporter 机制。MFC 的 VERIFY 宏便是一种在 debug 和 release 版都工作的断言,见 Using VERIFY Instead of ASSERT
缺点是,打开断言会降低程序性能(对断言表达式求值,及判断求值结果是否为零的分支)。应在效率敏感点,如将内循环中的断言关闭,而在其它不太影响程序整体性能的地方,将断言打开。也可以实现类似日志级别的断言级别机制,两者区别是,日志级别控制工作在运行时,而断言级别控制是根据级别的不同,在编译期消除掉断言语句。
基础库内建的 assert 可能无法满足这些要求,需要自己定制 assert。
breaker对本书的所有笔记 · · · · · ·
-
要点记录:设计模式
第29条 在现实世界中抛球杂耍 交互式应用常用的解耦设计模式: 1. FSM 有限状态机 2. observe...
-
要点记录:设计原则、过程方法
第10条 正交性 正交 orthogonal 这个词源自数学,工程设计上指模块、组件之间的独立性或解耦...
-
要点记录:契约式设计
-
要点记录:变换式编程
第30条 变换式编程 思想来源于 Unix shell 编程文化,用管道将单一功能的程序串联起来,完成...
-
要点记录:资源平衡
第26条 如何保持资源的平衡 [糟糕的设计] 用函数之间共享的资源句柄,这里是 customer_file ...
说明 · · · · · ·
表示其中内容是对原文的摘抄