《More Exceptional C++》序言 古希腊哲学家苏格拉底通过向学生提问进行教学。那些问题被设计用于引导他们,帮助他们从已知的东西得出结论,还向他们展示正在学习的东西是如何相互联系的,又如何与他们已有的知识相互联系。这种教学方式是如此著名,以至于今天我们称之为“苏格拉底教学法”。从我们作为学生的观点来看,苏格拉底的教学方法能够吸引我们的兴趣,促使我们思考,并帮助我们联系并应用我们已知的知识去获得新知识。 本书与其姊妹篇《Exceptional C++》[Sutter00]一样,借鉴了苏格拉底的方法。本书假定你正身处编写产品级C++软件的某些领域,它使用问答的形式教你如何有效地使用标准C++及其标准库,并特别关注于在现代C++中实施健全的软件工程。很多问题都直接来源于我和其他人在编写产品级C++代码时所积累的经验。问题的目标在于帮助你从已知的以及刚学到的东西中得出结论,并展示它们之间是如何相互联系的。而谜题则向你展示如何对C++设计和编程问题作出理性的分析。其中有些是常见的议题,有些则不那么常见;有些问题很简单,有些则比较深奥;还有一些问题只是因为它们有意思才出现于书中。 本书涵盖C++的方方面面。我的意思并不是说它触及了C++的每一个细节——那将需要多得多的篇幅,而是指它从C++语言和库特性之广阔的原料中选取素材,向你展示看似无关的特性是如何被综合使用的,从而形成针对常见问题的新颖的解决方案。本书还展示了那些看似无关的部分是如何相互关联的(即便有时你不希望它们之间有什么关联)以及如何处理这些关联。你将在本书中看到关于模板与名字空间、异常与继承、健壮的类设计与设计模式、泛型编程与宏的使用魔法等内容。它们并非以随意花边新闻的形式出现,而是以具有内在联系的条款的形式,向你展示现代C++中所有这些部分之间的相互关系。 何谓“more”? 《More Exceptional C++》从《Exceptional C++》停步的地方继续前行。本书继承了第一本书的传统:它以短小精悍的条款为组织形式,并将这些条款分组为主题明确的章节,以介绍新知识。读过第一本书的读者会发现一些熟悉的章节和主题,不过现在包含了新内容,例如异常安全、泛型编程以及内存管理技术等。这几本书在结构和主题而非内容上有重叠之处。 《More Exceptional C++》还有何不同之处呢?本书更加强调泛型编程和有效地使用C++标准库,包括对诸如特征萃取(traits)和判断式(predicates)这样的重要技术的讨论。一些条款对使用标准容器和算法时的注意事项提供了深入观察,其中许多注意事项我尚未在别处看到有所提及。一个新章节和两个附录集中于单线程和多线程环境下的优化,对于编写产品级代码的开发公司而言,这些议题现在比以往任何时候都具有更实际的重要意义。 书中的大多数条款最初出现于Internet和杂志专栏上,尤其出自“Guru of the Week”[GotW]的议题31到62,以及我为《C/C++ Users Journal》、《Dr. Dobb’s Journal》、《C++ Report》(已停刊)以及其他出版物撰写的专栏和文章。与最初的版本相比,本书中的材料经过大幅修订、扩充、校正和更新,因而本书(连同www.gotw.ca上不可或缺的勘误表)应被视作那些原始材料之最新权威版。 我假定你已经知道的 我期望你已经掌握了C++基础知识,如果你还没有,可以一本介绍性和概览性的C++好书开始学习。像Bjarne Stroustrup的《The C++ Programming Language》(第3版)[Stroustrup00]或Stan Lippman和Josée Lajoie合著的《C++ Primer》(第3版)[Lippman98]这样的经典都是优秀的选择。接下来,务必选读一本编程风格指南,例如Scott Meyers的经典著作《Effective C++》系列[Meyers96][Meyers97]。我发现基于浏览器的CD版[Meyers99]方便且实用。 如何阅读本书 书中的每一个条款都以迷题或问题的形式呈现,并带有一个引介性的头部,如下所示: Item##. 该谜题的标题 Difficulty: X 标题和难度等级提示你将要遭遇到什么。注意,难度等级只是我对自己预期大多数人发现问题有多难的主观猜测,因此,你也许会发现对你而言一个难度等级为7的问题比某个难度等级为5的问题来得更简单。自从写作《Exceptional C++》以来,我就不断收到一些电子邮件,说“条款N比你说的要容易(或困难)!”对于同一个条款而言,不同的人认为“更容易”或“更困难”是很正常的。难度等级因人而异,任何条款实际难度取决于你的知识和经验,它们对于其他人而言则可能更容易或更困难一些。话虽如此,大多数情况下你应该发现这些难度等级对你将要看到的内容(的难度)还是给出了合理的提示。 你也许打算从头至尾按顺序阅读本书,这很好,但你未必非得这样不可。你也许决定阅读某个特定章节中的所有条款,因为你对该章节的主题特别感兴趣,这同样很好。除了被我称为“小型系列”的那些被标以“Part 1”、“Part 2”等条款讨论的是相关的问题外,书中条款通常是相当独立的,因此你可以遵循条款之间的交叉引用以及对前两本“Exceptional C++”系列书籍的引用,自由地跳着读。我唯一要忠告的是,那些“小型系列”要成组按顺序阅读,除此之外,如何阅读全看你的喜好。 名字空间、typename、引用及其他约定 在书中我给出了不少建议,但我不会给你这样的指导方针:叫你去做连我自己都没做过的事。这包括我在整本书中我自己的示例代码中做的事。我还随既有实践和现代风格的大流,即便有时这并无实质性的影响。 在这方面,有必要说一下名字空间。在示例代码中,如果你在一个例子中看到一个文件范围的using指令,而在几页或几个条款之后的另一个例子中看到函数范围的using指令,这并没有什么深层次的原因,只是说明在该特定的情形下,那种用法是合适的,并且带给我美学上的愉悦,如是而已。如欲了解名字空间的基本原理,可阅读条款40。在正文中,当我想强调正在讨论的是标准库设施时,我会使用以std::限定的标准库名字,一旦确立了这一点,我通常重新使用非资格限定名字。 谈及模板参数的声明,我不时碰到一些人说写class而不是typename是过时的做法,即便这二者之间并无功能上的差别,而且标准文档自身都到处使用class。纯粹出于对风格的考虑,并且强调本书是关于今天的现代C++的,我已经转而使用typename而不是class来声明模板参数了。唯一的例外是在条款33中的某一处,由于那是我直接从标准中摘来的,标准使用的是class,我也就懒得动它了。 除非我明确指出某段代码是一个“完整的程序”,否则它很可能不是。记住,代码示例通常只是代码片段或部分的程序,别指望它们能被独立编译。为了从这些代码片段构建出完整的程序,通常你需要补充一些显而易见的边角代码。 最后,关于URL有必要多说一句:在Web上,东西会动来动去。尤其是,我无法控制的一些材料会动来动去。这使得在印刷书籍上刊印随意的Web URL就变成了真正的痛苦:恐怕在该书下厂印刷之前那些URL就已经过时了,更不要说等它在你的书桌上躺上5年之后了。当我在本书中引用他人的文章或Web站点时,我是通过自己的Web站点(www.gotw.ca)上的URL做到这一点的——我自己的Web站点是我所能控制的,它只包含对实际Web网页的重定向链接。如果你发现印刷在本书中的一个链接不再有效,请写邮件告诉我,我将更新该链接,使其指向新的网页位置(如果我还能找到该网页的话),或者告诉你该网页已不复存在(如果我找不到的话)。不管怎么说,本书的URL将会保持为最新,尽管在这个Internet世界中印刷媒体的日子是如此难过。呜呼! 致谢 非常感谢丛书编辑Bjarne Stroustrup,感谢Debbie Lafferty、Tyrrell Albaugh、Chanda Leary-Coutu、 Charles Leddy、Curt Johnson以及Addison-Wesley团队的其他成员,感谢他们对这个项目的协助和坚持。很难想象还有比他们更好的共事伙伴。他们的热情和协作精神使我对这本书的所有期望都得到了实现。 还有一群人值得感谢和赞扬,就是许多专家审稿人。他们慷慨地提供了富有洞察力的见解并对书稿中的纰漏提出犀利的批评。他们的努力使得你手中的这本书更完整、更可读、更有用。特别感谢(排名大致以我收到审阅意见的顺序)Scott Meyers、Jan Christiaan van Winkel、Steve Dewhurst、Dennis Mancl、Jim Hyslop、Steve Clamage、Kevlin Henney、Andrew Koenig、Patrick McKillen以及一些不知名的审稿人。书中残存的任何错误、疏忽和不谦虚的双关语,与他们无关,责任全在我自己。 最后,特别感谢我的家人和朋友,感谢你们在本书写作过程中以及其他时间一直陪伴在我身边。 Herb Sutter 荣耀 译 |