Exceptional C++ Style序言

场景:布达佩斯。一个炎热的夏天傍晚,穿过多瑙河望去,一直望见东岸。

在本书封面照片所展示的色彩柔和的欧洲风光中,首先映入你眼帘的是哪一栋建筑?几乎可以肯定是左边的国会大厦。这栋巨大的新哥特式建筑以其优美的圆穹、直插云霄的尖塔、大量的外部雕刻以及其他华丽的装饰会在刹那之间抓住你的目光,不过这更可能是因为它与周围的那些多瑙河畔刻板的实用主义建筑形成了鲜明的对比。

为何有此差异?原因首先在于国会大厦竣工于1902年,而其他刻板的实用主义建筑大都是在二战以后至1989年之间刻板而奉行实用主义的XX主义年代建成的。

你可能会想,啊哈,这解释了为何有此差异,不错,但这与《Exceptional C++ Style》到底有啥关系呢?

毋庸置疑,对风格的表达与注入的哲学和思想倾向有很大的关系,不管我们是在谈论建筑架构还是软件架构,都是如此。我敢肯定你见过有着国会大厦那般规模和华丽的软件,也见过差劲的实用主义软件。极端地说,我还确信你见过不少过于追求风格华而不实的软件,以及很多只顾交差了事的丑小鸭(而且永远都不会变成白天鹅)。

风格抑或实用?

哪一个更好? 

不要过于自负你知道答案。首先,除非你定出明确的标准,否则更好只是一个无意义的术语——针对什么而言更好?在哪些情形下更好?其次,答案几乎总是这两者的平衡并以这取决于……开始。 

本书就是关于如何在C++软件设计和实现的诸多细节方面找到平衡点,以及很好地了解你手头的工具和原料以便知道它们何时适于使用。 

请快速回答:与周围单调乏味的建筑相比,国会大厦是更好的建筑吗?它的建筑风格更好吗?在不假思索的情况下你很容易给出肯定的回答——直到你不得不考虑其建造和维修的代价: 

l          建造。在1902年竣工之时,它是世界上最大的国会大厦。人们花费了恐怖的时间、劳动和金钱来建造它,它被很多人认为是大白象,意指代价过高的美丽事物。不妨考虑一下:相较而言,花费同样的投资能够建造多少丑陋、单调甚至可能完全令人厌烦的混凝土建筑?别忘了,你工作于这样的一个行业:产品上市的压力远远超过建造该国会大厦所处时代的时间压力。 

l          维修。你们中熟悉国会大厦的人会注意到照片中的建筑正处于翻修中,此项工作已经持续好多年了,极有争议性地耗费了可怕的资金。除了最近这轮代价高昂的翻修外,此前已有过多次维修。原因在于——悲哀的是,你看到的这座建筑外部美丽的雕刻是用错误的材料制成的:这种材料太软了。在大厦最初竣工后不久,这些雕刻就成了人们持续维修的主题,它们已逐渐被替换为更坚固、更耐久的材料。始于19世纪早期的大规模维修自那以后一直没间断过,持续了近一个世纪。 

软件的情形与之类似,重要的是在建造代价与功能之间、在优雅与可维护性之间、在发展的可能性与过分的华丽之间寻找适当的平衡点。 

当使用C++实施软件设计和架构时,我们每天都要处理这些以及类似的权衡。在本书探讨的问题中有这样一些:使你的代码异常安全就会使它变得更好吗?果真如此,这里的更好是针对什么而言呢?何时它可能并非更好?该问题在书中有着明确的答案。封装又如何呢?它使你的软件变得更好吗?为什么?何时封装效果适得其反?如果你对此心存疑惑,请接着读下去。内联是一种好的优化手段吗?它是何时进行的呢?(回答这个问题时你千万慎之又慎)C++中的export特性和国会大厦有何相通之处?std::string与多瑙河畔的整体建筑之间又有何共同点? 

最后,在探讨许多C++技术和特性之后,我们将花费本书末尾一节考察一些摘自公开发布的代码的真实例子,看其作者在哪些方面做得不错,在哪些方面做得欠佳,以及什么样的替代方案可能在实用性和优秀的C++风格(exceptional C++ style)之间取得更好的平衡点。 

我希望这本书以及《Exceptional C++》系列的其他书籍对你有何帮助呢?呃,我希望它们能够开阔你的视野,扩大你在技术细节及其相互关系方面的知识,并且增添你对如何找到软件开发平衡点的理解。 

请再看一眼封面照片的右上方,对,就是那儿!我们都希望乘坐在那样的热气球中,飘荡在城市的上空,饱览美妙的全景。我们将会看看风格和实用性是如何共存、互动、关联和混合的,了解如何进行权衡并找到适当的平衡点,每一个决策都适得其所,并位于一个生机盎然的有机整体中。 

是的,我认为布达佩斯是一个伟大的城市,它具有如此丰富的历史,它充满无尽的隐喻。 

非凡的苏格拉底 

古希腊哲学家苏格拉底通过向学生提问进行教学。那些问题被设计用于引导他们,并帮助他们从已知的东西得出结论,还向他们展示正在学习的东西是如何相互联系的,又如何与他们已有的知识相互联系。这种教学方式是如此著名,以至于今天我们称之为苏格拉底教学法。从我们作为学生的观点来看,苏格拉底传奇性的教学方法能够吸引我们的兴趣,促使我们思考,帮助我们联系并应用我们已知的知识去获得新知识。 

本书与其姊妹篇《Exceptional C++[Sutter00]和《More Exceptional C++[Sutter02])一样,借鉴了苏格拉底的方法。本书假定你正身处编写产品级C++软件的某些领域,它使用问答的形式教你如何有效地使用标准C++及其标准库,并特别关注于在现代C++中实施健全的软件工程。很多问题都直接来源于我和其他人在编写产品级C++代码时所积累的经验。问题的目标在于帮助你从已知的以及刚学到的东西中得出结论,并展示它们之间是如何相互联系的。而谜题则向你展示如何对C++设计和编程问题作出理性的分析。其中有些是常见的议题,有些则不那么常见;有些问题很简单,有些则比较深奥;还有一些问题只是因为它们有意思才出现于书中。 

本书涵盖C++的方方面面。我的意思并不是说它触及了C++的每一个细节——那将需要多得多的篇幅,而是指它从C++语言和库特性之广阔的原料中选取素材,向你展示看似无关的特性是如何被综合使用的,从而形成针对常见问题的新颖的解决方案。本书还展示了那些看似无关的部分是如何相互关联的(即便有时你不希望它们之间有什么关联)以及如何处理这些关联。你将在本书中看到关于模板与名字空间、异常与继承、健壮的类设计与设计模式、泛型编程与宏的使用魔法等内容。它们并非以随意花边新闻的形式出现,而是以具有内在联系的条款的形式,向你展示现代C++中所有这些部分之间的相互关系。 

Exceptional C++ Style》从《Exceptional C++》和《More Exceptional C++》停步的地方继续前行。本书继承了前两本书的传统:它以短小精悍的条款为组织形式,并将这些条款分组为主题明确的章节,从而介绍新知识。读过前两本书的读者会发现一些熟悉的章节和主题,不过现在包含了新内容,例如异常安全、泛型编程以及优化和内存管理技术等。这几本书在结构和主题而非内容上有重叠之处。本书持续了对泛型编程和有效地使用C++标准库的强调,并包括对一些重要的模板和泛型编程技术的讨论。 

书中的大多数条款最初出现于杂志专栏和Internet上,尤其出自我为《C/C++ Users Journal》、《Dr. Dobb’s Journal》、《C++ Report》(已停刊)以及其他出版物撰写的专栏和文章,以及我的“Guru of the Week[GotW]的议题6386。与最初的版本相比,本书中的材料经过了重大的修订、扩充、校正和更新,因而本书(连同www.gotw.ca上不可或缺的勘误表)应被视作那些原始材料之最新权威版。

我假定你已经知道的 

我期望你已经掌握了C++基础知识,如果你还没有,可以一本介绍性和概览性的C++好书开始学习。像Bjarne Stroustrup的《The C++ Programming Language》(第3版)[Stroustrup00]Stan LippmanJosée Lajoie合著的《C++ Primer》(第3版)[Lippman98]这样的经典都是优秀的选择。接下来,务必选读一本编程风格指南,例如Scott Meyers的经典著作《Effective C++》系列[Meyers96, Meyers97]。我发现基于浏览器的CD[Meyers99]方便且实用。 

如何阅读本书 

书中的每一个条款都以迷题或问题的形式呈现,并带有一个介绍性的头部,如下所示: 

##. 本条款的标题 

Difficulty: # 

对该条款将要讨论的内容的简短介绍。 

标题和难度等级提示你将要遭遇到什么。在主要问题(即Guru问题)之前通常是介绍性或回顾性的问题(即“JG问题”,其中JGjunior-grade)意指新来的下级军官)。注意,难度等级只是我对自己预期大多数人发现问题有多难的主观猜测,因此,你也许会发现对你而言一个难度等级为7的问题比某个难度等级为5的问题来得更简单。实际上,自从写作《Exceptional C++[Sutter00]和《More Exceptional C++ [Sutter02]以来,我就不断收到一些电子邮件,说条款N比你说的要容易(或困难)!对于同一个条款而言,不同的人认为“更容易”或“更困难”是很正常的。难度等级因人而异,任何条款实际难度取决于你的知识和经验,它们对于其他人而言则可能更容易或更困难一些。话虽如此,大多数情况下你应该发现这些难度等级还是对你将要看到的内容(的难度)给出了相当合理的提示。 

你也许打算从头至尾按顺序阅读本书,这很好,但你未必非得这样不可。你也许决定阅读某个特定章节中的所有条款,因为你对该章节的主题特别感兴趣,这同样很好。除了被我称为“小型系列”的那些被标以“Part 1”Part 2等条款讨论的是相关的问题外,书中条款通常是相当独立的,因此你可以遵循条款之间的交叉引用以及对前两本“Exceptional C++”系列书籍的引用,自由地跳着读。我唯一要忠告的是,那些“小型系列”要成组按顺序阅读,除此之外,如何阅读全凭你的喜好。 

除非我明确指出某段代码是一个完整的程序,否则它很可能不是。记住,代码示例通常只是代码片段或部分的程序,别指望它们能被独立编译。为了从这些代码片段构建出完整的程序,通常你需要补充一些显而易见的边角代码。 

最后,关于URL有必要多说一句:在Web上,东西会动来动去。尤其是,我无法控制的一些材料会动来动去。这使得在印刷书籍上刊印随意的Web URL就变成了真正的痛苦:恐怕在该书下厂印刷之前那些URL就已经过时了,更不要说等它在你的书桌上躺上5年之后了。当我在本书中引用他人的文章或Web站点时,我是通过自己的Web站点(www.gotw.ca)上的URL做到这一点的——我自己的Web站点是我所能控制的,它只包含对实际Web网页的重定向链接。几乎所有在书中引用到的其他作品都已列在参考文献中了,而且在我的网站上还提供了一份具有活动超链接的在线版本。如果你发现印刷在本书中的一个链接不再有效,请写邮件告诉我,我将更新该链接,使其指向新的网页位置(如果我还能找到该网页的话),或者告诉你该网页已不复存在(如果我找不到的话)。不管怎么说,本书的URL将会保持为最新,尽管在这个Internet世界中印刷媒体的日子是如此难过。呜呼! 

致谢 

首先感谢我的妻子Tina,感谢她一贯的爱和支持。感谢我的家人在我写作本书和其他作品期间一直陪伴在我左右。即使当我不得不挑灯夜战写作另外一些文章或修改另外一些条款时,他们也总是表现出无尽的耐心。倘若没有他们的耐心和关爱,本书就绝不会有现在这般模样。 

我们的小狗Frankie也付出了宝贵的贡献。当我工作时它常常希望我陪它玩,这强迫我不时 到户外呼吸一些新鲜空气。Frankie对软件架构或程序语言设计甚至代码微观优化一无所知,但它过得非常快乐。 

非常感谢丛书编辑Bjarne Stroustrup、编辑Peter GordonDebbie Lafferty,还要感谢Tyrrell AlbaughBernard GaffneyCurt JohnsonChanda Leary-CoutuCharles LeddyMalinda McCainChuti Prasertsith以及Addison-Wesley编辑团队的其他成员,感谢他们对这个项目的协助和坚持。很难想象还有比他们更好的共事伙伴。他们的热情和协作精神使我对这本书的所有期望都得到了实现。 

还有一群人值得感谢和赞扬,就是许多专家审稿人。他们慷慨地提供了富有洞察力的见解并对书稿中的纰漏提出犀利的批评。他们的努力使得你手中的这本书更完整、更可读、更有用。尤其感谢他们向丛书编辑Bjarne Stroustrup提供的技术反馈。还要感谢在本书写作过程中为它的各个部分提出贡献性建议的以下各位人士:Dave AbrahamsSteve AdamczykAndrei AlexandrescuChuck AllisonMatt AusternJoerg BarfurthPete BeckerBrandon BraySteve DewhurstJonathan CavesPeter Dimov Javier Estrada, Attila Fehér, Marco Dalla Gasperina, Doug Gregor, Mark Hall, Kevlin Henney, Howard HinnantCay HorstmannJim HyslopMark E. KaminskyDennis ManclBrian McNamaraScott Meyers Jeff PeilJohn PotterP. J. PlaugerMartin SeborJames SlaughterNikolai SmirnovJohn Spicer Jan Christiaan van WinkelDaveed Vandevoorde以及Bill Wade。书中残存的任何错误、疏忽和不谦虚的双关语,与他们无关,责任全在我自己。

Herb Sutter
20045月于
西雅图

荣耀 译
200
61
南京师范大学

www.royaloo.com