《Imperfect C++中文版》——第1章 强制设计:约束、契约和断言

简介:

第1章 强制设计:约束、契约和断言

Imperfect C++中文版
在我们设计软件时,我们希望软件根据设计而进行使用。这并非一句空话。在大多数情况下,很容易发生以意料之外的方式来使用软件,而这么做的结果往往是令人失望的。

大多数软件的文档几乎都是不完整,甚至是过时的,我坚信你也有这方面的经验。这并非单纯的错误或缺失,“如果还有比没有文档更糟的情形,那就是文档是错误的”[Meye1997]。如果被使用的组件比较简单,使用得当,或者说是标准的或被普遍使用的,那么没有文档倒也不是什么大问题。例如,如果许多程序员需要一而再、再而三地查找C库函数malloc()的用法,那可真算是奇闻怪谈了。然而,这种情况毕竟很少。我曾经遇到一些程序员,他们非常有经验,但对malloc()的兄弟realloc()和free()之间的细微差别却并不那么熟悉。

对于这些问题,解决的方式很多。其一是通过增强的参数验证,使软件组件具有更强的抵抗错误的能力,但这种方式通常不那么有吸引力,因为它会损及性能,还倾向于滋生坏习惯。制作良好的文档并让它们保持更新当然是解决方案的一个重要组成部分,然而这种做法是远远不够的,因为它是“非强制性”的。此外,要想写出好文档也是一件极其困难的事情[Hunt2000]。软件越复杂,其原始作者要想把自己摆在对该软件懵懂无知的处境从而便于写出更好的说明文档就越不可能,而独立的技术作者要想抓住其所有的细微之处就更加困难了。因此,当情况不再单纯时,一个确保正确使用代码的更好的方式显然是必不可少的。

如果编译器能够为我们找出错误那就更可取了。事实上,本书中的相当一部分内容都是关于如何驱使和利用编译器,令它在碰到糟糕的代码时卡壳,从而便于我们在编译期及早抓住错误。但愿你能够意识到花几分钟来安抚编译器比花上几个小时和调试器纠缠要好得多。正如Kernighan和Pike在The Practice of Programming[Kenm1999]中所说的那样,“无论你喜欢与否,调试是一门我们经常要实践的艺术……如果不产生bug就好了,所以我们尝试在第一时间就把代码写正确,从而尽量避免bug的产生。”由于我并不比其他软件工程师更勤快,因此我总是尽量让编译器帮我做事情。从长远来看,“苦行僧”式的编程是比较容易的选择。然而,并非所有的错误都能够在编译期查出来。在这种情况下,我们需要求助于运行期机制。一些语言(例如D和Eiffel)提供了内建的机制,即通过“契约式设计(Design by Contract,Dbc)”来确保软件按照其设计而被使用。此项技术的先驱是Bertrand Meyer[Meye1997],它源于程序的形式验证。契约式设计要求为软件组件指定“契约”,这些契约会在程序运行过程中的某些特定点被强制执行。契约在很多方面都可以作为文档的替代品,因为它们无法被忽略,并且是自动进行验证的。此外,通过遵循特定的语法约定,它就可以和自动化文档工具合作,我们将会在1.3节对此进行讨论。

实施“强制(enforcement)”的机制之一是断言(assertion),包括广为人知的运行期断言,以及较少为人知然而甚至更为有用的编译期断言。本书中两者均得到了大量的使用,因此我们将会在1.4节对这种重要的工具进行详细的观察。

本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关文章
|
3月前
|
编译器 API C++
c++ 新特性 概念和约束 “无规矩 难成方圆”
c++ 新特性 概念和约束 “无规矩 难成方圆”
|
存储 Java 应用服务中间件
线程池设计, 从简单的我们平常设计线程池图解,到生活中的类似线程池的处理现实场景, 到简单的C++模拟nginx写的单链表组织工作队列的简单线程池实现 + nginx 部分源码刨析
线程池设计, 从简单的我们平常设计线程池图解,到生活中的类似线程池的处理现实场景, 到简单的C++模拟nginx写的单链表组织工作队列的简单线程池实现 + nginx 部分源码刨析
线程池设计, 从简单的我们平常设计线程池图解,到生活中的类似线程池的处理现实场景, 到简单的C++模拟nginx写的单链表组织工作队列的简单线程池实现 + nginx 部分源码刨析
|
架构师 数据挖掘 程序员
C++ 类设计和实现的十大最佳实践
C++ 类设计和实现的十大最佳实践
577 0
C++ 类设计和实现的十大最佳实践
|
设计模式 测试技术 uml
[学习][笔记]设计模式(基于C/C++实现)之 设计基础
设计模式(基于C/C++实现)之 设计基础
357 0
[学习][笔记]设计模式(基于C/C++实现)之 设计基础
C++编程练习:多态实验——设计一个基类Shapes,Shapes类公有派生产生矩形类Rectangle和圆类Circle
C++编程练习:多态实验——设计一个基类Shapes,Shapes类公有派生产生矩形类Rectangle和圆类Circle
C++编程练习:多态实验——设计一个基类Shapes,Shapes类公有派生产生矩形类Rectangle和圆类Circle
C++编程练习:设计一个银行账户类,包含户名、帐号以及当前余额属性,并且能完成开户、存款、取款和查询余额等行为。
C++编程练习:设计一个银行账户类,包含户名、帐号以及当前余额属性,并且能完成开户、存款、取款和查询余额等行为。
C++编程练习:设计一个银行账户类,包含户名、帐号以及当前余额属性,并且能完成开户、存款、取款和查询余额等行为。
|
编译器 C++
C++把类的设计看成类型设计
C++把类的设计看成类型设计
88 0
|
安全 NoSQL JavaScript
C/C++为什么要专门设计个do…while?
最初do ... while的出现,更多的是作为循环控制流的一种语法糖。因为不论是while 还是 for循环,都是要先判断是否满足进入循环体的条件的。满足条件之后才能进入循环去执行循环体内的操作。
147 0
C/C++为什么要专门设计个do…while?
|
安全 前端开发 rax
「现代C++设计魅力」虚函数继承-thunk技术初探
工作中使用LLDB调试器调试这一段C++多继承程序的时候,发现通过lldb print(expression命令的别名) 命令获取的指针地址和实际理解的C++的内存模型的地址不一样。那么到底是什么原因呢?
「现代C++设计魅力」虚函数继承-thunk技术初探
|
网络协议 Ubuntu Linux
基于C++(QT框架)设计的网络摄像头项目(支持跨平台运行)
基于C++(QT框架)设计的网络摄像头项目(支持跨平台运行)
872 0
基于C++(QT框架)设计的网络摄像头项目(支持跨平台运行)