《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节对这种重要的工具进行详细的观察。

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

时间: 2024-09-20 00:54:52

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

《Imperfect C++中文版》导读

前 言 Imperfect C++中文版 或许我不像喜欢我的孩子们那样喜爱C++,甚至或许我对C++的喜爱都比不上我对骑自行车在坡度为32°.光滑度为10%的柏油路上爬坡的热衷,1尽管有时这些喜爱之情的确十分接近.我庆幸我有这样的人生,让我得以将生命中的部分时间用来实践或阐释Frederick P.Brooks的名言:"尽量发挥想象力进行创造".我更要感激的是我能够跟这门如此强大.危险却又诱人的语言相伴. 这些话听起来似乎蛮华丽动听,但你可能是因为看到本书的书名才买下它的,以为本书是一

《Imperfect C++中文版》——第2章 对象生命期

第2章 对象生命期 Imperfect C++中文版本文仅用于学习和交流目的,不代表异步社区观点.非商业转载请注明作译者.出处,并保留本文的原始链接.

《Imperfect C++中文版》——1.3 运行期契约:前置条件、后置条件和不变式

1.3 运行期契约:前置条件.后置条件和不变式 Imperfect C++中文版 "如果例程的所有前置条件(precondition)已经被调用者满足了,那么该例程必须确保当它完成时所有后置条件(postconditions)(以及任何不变式)皆为真."--Hunt and Thomas, The Pragmatic Programmers [Hunt2000]. 如果我们无法执行编译期强制,那么还可以采用运行期强制.运行期强制的一个系统化的实现途径是指定函数契约.函数契约精确定义了在

《Imperfect C++中文版》——2.2 控制你的客户端

2.2 控制你的客户端 Imperfect C++中文版 C++的一个重要且强大的特性是在编译期实施访问控制的能力.通过使用public.protected以及private[Stro1997]访问限定关键字,以及适当地使用friend关键字,我们可以控制客户端代码使用我们的类型的方式.这种控制在很多方面都是极其有用的,本书中就有很多技术利用了这种能力. 2.2.1 成员类型 控制外界对你的类实例的操纵的强大方式之一,是将类的成员声明为const和/或引用类型.因为常量和引用(以及const引用

《Imperfect C++中文版》——1.2 编译期契约:约束

1.2 编译期契约:约束 Imperfect C++中文版本章讲述编译期强制,通常它也被称为"约束(constraints)".遗憾的是,C++并不直接支持约束. Imperfection: C++ 不直接支持约束.C++是一门极其强大和灵活的语言,因此很多支持者(甚至包括一些C++权威)都会认为本节描述的约束实现技术已经足够了.然而,作为C++和约束的双重拥护者,我必须提出我的异议(由于一些很平常的原因).虽然我并不买其他语言鼓吹者的账,然而我同样认为阅读因违反约束而导致的编译错误信

《Imperfect C++中文版》——2.3 MIL及其优点

2.3 MIL及其优点 Imperfect C++中文版 你会在构造函数中进行初始化的东西可能包括以下7种: 1.直接父类. 2.虚基类.1 3.常量型成员变量. 4.引用型成员变量. 5.non-const.non-reference.但"具有非缺省构造函数的用户自定义类型"的成员变量. 6.non-const.non-reference的标量型成员变量,我们可以把它们看成"常规的"成员变量. 7.数组作为成员变量. 在这7种中,只有最后一种,即数组型成员变量,不

《Imperfect C++中文版》——1.4 断言

1.4 断言 Imperfect C++中文版 在我看来,断言并非一个良好的报错机制,因为它们通常在同一个软件的调试版和发行版中的行为有着极大的差异.虽说如此,断言仍然是C++程序员确保软件质量的最重要的工具之一,特别是考虑到它被使用的程度和约束.不变式一样广泛.任何关于报错机制的文档,如果没有提到断言的话肯定不能算是完美的. 基本上,断言是一种运行期测试,通常仅被用于调试版或测试版的构建,其形式往往像这样: #ifdef NDEBUG # define assert(x) ((void)(0)

《Imperfect C++中文版》——2.1 对象生命周期

2.1 对象生命周期 Imperfect C++中文版 每个C++对象的生命周期都分为4段:不存在.部分构造.实例化.部分析构[Stro1997].此外,一个对象所占用的空间必须在该对象构造之前就分配好,并且在该对象析构之后被释放.1 对象可以以下例4种标准方式诞生. 全局对象,包括真正的"全局"对象.位于名字空间中的对象,以及作为类静态成员的对象,生存于任何函数的作用域之外.它们通常在main()函数被执行之前就已经构造完毕,并且在main()结束之后被自动销毁(见11.1节).它们

java 程序性能优化《第二章》设计优化 2.1善用设计模式 1 单例模式

java 程序性能优化<第二章>设计优化 2.1善用设计模式 1 单例模式 设计模式是前人工作的总结和提炼.通常,被人们广泛流传的设计模式都是对某一特定问题的成熟的解决方案.如果能合理的使用设计模式,不仅能使系统更容易被他人理解,同时也能使系统拥有更加合理的结构.本节总结归纳了一些经典的设计模式,并详细说明它们与软件性能之间的关系. 2.1.1 单例模式 单例模式是设计模式中使用最为普遍的模式之一.它是一种对象创建模式,用于生产一个对象的具体实现,它可以确保系统中一个类只产生一个实例.在Jav