【推荐序一】
在数字化世界的无垠海洋中,每一串代码都如同一艘航船,载我们驶向未知与创新的港口。而C++这种兼具效率与灵活性的编程语言,宛如这片海洋中一颗耀眼的星。从诞生到今日,C++不仅见证了计算机科学由抽象理念到现实应用的壮丽变迁,更激发了程序员们对编程艺术的热爱与探索精神。
《C++之美》这本书就像一位智慧的导师,以其深邃且富有诗意的语言,带领我们遨游C++的瑰丽世界,挖掘隐藏在复杂编程结构和算法背后的美学。此书不仅是技术的教科书,还带领我们探索编程的本质和艺术,让我们在熟练掌握C++的同时,体会到编程本身的乐趣与成就感。
我,作为《C++之旅》一书的译者,同时也是拥有二十余年一线C++编程实战经验的程序员。在翻译和研读这些权威著作时,我深切感受到,作者们并非纸上谈兵,而是真正投身工程实践,对C++的细枝末节有着深刻而独到的见解。
这本《C++之美》汲取了C++ Core Guidelines的精髓,并结合了作者十多年行业实战经验。这些源于真实项目的宝贵经验,对于所有热爱C++的编程者来说,都是无价的财富。
我坚信,《C++之美》将成为每位C++爱好者的宝贵手册。它不仅会伴随你度过那些漫长的编程夜晚,更会在你迷茫之际,成为指引你前行的明灯。让我们共同启航,在《C++之美》的指引下,感受编程的纯粹与魅力,书写自己的编程传奇。
愿此书成为你编程之路上的灯塔,为你照亮通往更高成就的道路。
——@pansz 《C++之旅》(第3版)译者,知乎关注人数过百万答主
【推荐序二】
许多程序员在多年工作后,竟然一年都无法完整读完一本技术书。尽管他们一年内可以在知乎和各类社交媒体上阅读数百万字的内容,却无法读完一本仅有50万字的书。这并不是因为他们太忙、没有时间,而是因为人类天生就偏爱碎片化的快餐信息。然而,越是珍贵的东西,越需要付出努力才能获得,知识也不例外。不进行系统性的学习和深入的思考,是无法获得真正宝贵的知识的。
有些技能只要投入一定时间学习就能掌握,比如打字、驾驶、学习一门新的编程语言;而且一旦掌握它们,你就会终身受益。在这些事情上投入时间,性价比最高。
实话说,今天学习C++比以前更具挑战性了。一方面,新标准的引入提高了C++的安全性和描述力,但也增加了学习的难度;另一方面,过去大部分软件都用C++来开发,新人入职后通常先从小模块的开发开始,再逐步扩展到中模块、大模块,通过学习老同事的代码,在生产领域不断实践,总能一步一步提高编程能力,最终能设计较为复杂的大型系统。然而,如今的新人并没有这种阶梯式的锻炼机会,他们的第一语言往往不是C++,而当他们用其他语言开发几年后遇到性能瓶颈需要用C++时,突然根本无法驾驭。
同时,掌握C++也成为一项愈加珍贵的技能。新兴行业最初的各种基础设施和工具,大多是用C++构建的。无论是十多年前的移动开发领域,还是四五年前的音视频领域,乃至当下热门的AI领域,都是如此。例如TFLite、whisper.cpp和llama.cpp等这些都是C++项目,其中llama.cpp在GitHub上线两周内就获得了20,000个星标。同时精通C++和Python的算法工程师,相较于只会Python的程序员,能获得更多机会,走得更远。
关于C++语法的知识,自己花点儿时间总能学会,但在实际项目中积累经验与领悟却需要很长时间。不少人过于专注于穷尽语法的各个细节,却忽略了对大型复杂项目驾驭能力的培养,结果就是谈起C++标准来头头是道,在项目中写点儿复杂代码就垮了。
本书提炼和归纳了C++工程实践中的难点。我初读的感受很像是对过往认知的一次印证,不少准则让我很有共鸣,比如优先使用函数默认参数而非重载,尽量减少可写变量的显示共享等,这些建议在项目初期可能不会显得特别重要,但随着项目复杂度的增加,忽视它们所带来的问题才会逐渐显现出来。更隐蔽的是,当项目变得难以维护时,很多人可能无法意识到正是这些问题的积累导致了困境。
有些准则所描述的问题真的是多年的开发者才会遇到的“暗坑”,比如跨ABI需要使用C风格接口,优先选择不可变数据而不是可变数据,没有多年的C++编程经验是完全总结不出这些准则的。本书挑出的30条核心准则能帮助大家更好地驾驭大型复杂C++项目。如果说Effective C++总结了许多微观层面的“避坑”建议,那么本书则提供了一份宏观层面的“避坑”指南,特别适合在学习完语法,完成一两个玩具项目之后,真正开始做一些严肃项目时阅读。
——@韦易笑 资深游戏开发专家
【译者序】
C++不是一门简单的编程语言,这一点从相关的书籍上便可见一斑。首先,几乎每一本C++基础教程都是大部头;其次,仅关于惯用法和最佳实践就已经形成系列,而且出现了不少经典著作,比如Scott Meyers的“Effective”系列,Herb Sutter的“Exceptional”系列,以及其他一些单本,如C++ Gotchas、C++ Coding Standards等。
C++语言的发展从未停滞,最佳实践也随之发展。2014年,C++之父Bjarne Stroustrup和ISO C++标准委员会主席Herb Sutter共同编辑并维护了《C++核心准则》(C++ Core Guidelines),这无疑是现代C++最佳实践的集大成者。而且,它是一份动态文档,到本书定稿时,新的编辑意见仍在提交和合并中。
目前,《C++核心准则》分为近20个大类,包含的条目800有余,远远超过了以往任何一本最佳实践图书的内容。依其初衷,也限于篇幅,每个条目往往只说结论,外加简短的解释。
鉴于此,本书的两位作者从中精心挑选了30条核心准则,为读者做详细的解释。通过这种突出重点、以点带面的方式帮助读者了解并学习《C++核心准则》。书中的内容远不止理论上的分析和探讨,更包含了作者数十年职业生涯中的经验和示例,因此很多的深刻见解都是通过故事娓娓道出的。这样的方式既能将问题讲透,又使阅读的体验相对轻松。
30条准则在《C++核心准则》中所占的比例虽然很小,但讲解的内容涉及C++语言的各个主要方面,如类型系统、面向对象、模板和元编程、错误处理、性能、常量性,当然还有编码风格,甚至某些设计模式。很多时候,作者在讲解一条准则的时候也会引用其他的准则。
在翻译本书的过程中,我跟随作者的思路,不仅更深入地领会了《C++核心准则》,对随着各版新标准的推出而不断成长的现代C++语言也有了更多感悟。此外,在翻译的过程中,我也时常遇到自己工作中经常思考的问题,对作者的论述心有戚戚焉,但作者的总结更加通透。
倘若有幸,我的转达是有效的,相信读者朋友也能从中领略很多。若有表达不清之处,那一定是翻译的问题,希望朋友们不吝指正。
有幸翻译本书完全出于电子工业出版社张春雨老师的抬爱和信任,对此不胜感激。然而翻译的周期远远超出了最初的计划,导致图书未能及早付梓而到达读者手中,对此更应感谢所有编辑老师的谅解,也恳请读者朋友见谅。
——王江平 于上海
【序】
我很享受阅读本书的过程。我享受它,尤其因为它以一种与《C++核心准则》(C++ Core Guidelines,CG)本身完全不同的方式呈现了C++的核心准则。CG以一种固定格式,相对简短地给出了各条准则。在CG中,这些准则通常是用编程语言的术语表达的,强调如何通过静态分析来实施。本书却在讲故事,很多故事来自经历了几十年代码和技术演化的游戏行业。它以开发者的视角讲解这些准则,强调遵循这些准则将会得到的好处,以及无视这些准则可能导致的噩梦。关于准则的动机,相比CG本身所阐述的内容,在本书中有更加广泛的讨论。
CG旨在达到一定程度的完整性。当然,一套关于如何编写优良代码的准则难以达到彻底的完整性,而必要程度的完整性则意味着CG并不适合系统性阅读。我推荐各位阅读CG的前言和哲学部分,以了解其目标和概念框架。但是,如果要在品味、视角和经验的指导下有选择地了解CG,那就阅读本书吧。对真正的极客来说,本书是轻松有趣的读物。对大多数软件开发者来说,它提供了新的、有用的东西。
——Bjarne Stroustrup
【前 言】
随着每一版C++新标准的到来以及每一种新教程的出现,编写C++代码的复杂性逐渐降低。相关的会议、博客和书籍比比皆是,这是好事。世界上并没有足够多的高素质工程师来解决我们面临的实际问题。
尽管C++语言不断简化,但就如何编写好的C++代码而言,仍有很多东西需要学习。C++的发明者Bjarne Stroustrup和维护C++标准的机构的召集人Herb Sutter投入了大量精力来创作关于学习C++和编写更好的C++代码的教材。这些教材包括:The C++ Programming Language[ Bjarne Stroustrup著,Addison-Wesley出版。中文版名为《C++程序设计语言(第1-3部分)》(原书第4版),由机械工业出版社于2016年出版。]、A Tour of C++[ Bjarne Stroustrup著,Addison-Wesley出版。中文版名为《C++之旅》(第3版),由电子工业出版社于2023年出版。],以及Exceptional C++[ Herb Sutter 著,Addison-Wesley出版。同名中文版由电子工业出版社于2012年出版。]和C++ Coding Standards[ Herb Sutter与Andrei Alexandrescu合著,Addison-Wesley出版。中文版名为《C++编程规范》,由人民邮电出版社于2016年出版。]。
书的问题在于它代表的是事物发展的一种时间快照,本书也一样。然而C++是一门不断发展的语言,1998年的好建议拿到现在来看或许就不再是明智之举了。编程语言在不断发展,相应的准则也要不断发展。
在2015年的CppCon上,Bjarne Stroustrup[ 可以在YouTube上观看Bjarne Stroustrup的演讲视频,演讲题目为“Writing Good C++14“。]和Herb Sutter[ 可以在YouTube上观看Herb Sutter的演讲视频,演讲题目为“Writing Good C++14... By Default”。]在他们各自的主题演讲中都发布了一份在线文档——《C++核心准则》[ C++ Core Guidelines,版权所有者为Standard C++ Foundation及其贡献者。可访问isocpp.github.io网站获取。]。该准则为改善C++代码风格提供了出色而简单的建议。只要遵循这些建议,你从一开始就能写出正确且高效的C++代码。它是C++从业者所需要的指导手册,而且它本身也在不断改进,作者们都很乐意审阅那些提出修正或改进意见的拉取请求(pull request)。从C++初学者到老手,每个人都应该遵循这些建议。
2020年2月底,Kate Gregory在“#include C++”的Discord聊天组[ #include 是一个全球性、多元化、包容的C++开发者社区(网站名为includecpp)。社区的交流平台为其Discord服务器。]中表示打算写一本关于C++核心准则的书,我小心翼翼地抓住了这个机会。Kate在2017年的CppCon[ 可以在YouTube上观看Kate Gregory的演讲视频,演讲题目为“10 Core Guidelines You Need to Start Using Now”。]上做过一次演讲,其中只提到了《C++核心准则》中的10条。我和她一样,对推动程序设计向更好的方向发展满怀热情。我在英国成立时间最久、规模最大的游戏开发工作室Creative Assembly担任工程实践主管,在过去的20多年里,我花了很多时间帮助我们的优秀工程师成长为卓越的工程师。据我们观察,尽管《C++核心准则》简单易懂,但许多开发者对它并不是特别熟悉。我们想宣传那些准则,让更多人用起来,于是决定写这本书,因为相关的书还不够多。
《C++核心准则》里面都是非常好的建议,让人不知道从哪里开始看比较好。你可以从头读到尾,但需要反复阅读,否则很难掌握全部的内容。这些建议被分成22部分,冠以“接口”“函数”“并发”之类的标题。每一部分都是由一条条的准则组成的,有的部分有几条,有的部分则有几十条。每一条准则使用所属部分的标题首字母,加上它在这一部分中的编号来标识,中间用点号隔开。例如,“F.3: Keep functions short and simple”(F.3:保持函数简短)是“Functions”这一部分中的第3条准则。
每条准则都以相同的方式编排。首先是准则的标题。标题通常描述的是一种动作(这样做、不这样做、避免这样做、首选这样做等),然后是理由和一些示例,可能还有例外的情形。最后还有一条关于如何实施该准则的说明。说明的内容多种多样,有给静态分析工具开发者的建议,也有如何进行代码审阅的提示。事实上,阅读这些准则是有技巧的,而决定在自己的代码中优先考虑哪些准则属于个人发现(personal discovery)的范畴[ 译注:意思是在阅读和理解准则时应独立思考和判断。这里强调了准则的执行是一个因人而异的个体化的过程。]。我们希望传递关于如何利用核心准则的智慧。
C++中有一些尖锐的棱角,也有一些积灰的角落,它们在现代C++中不常出现。我们想让大家远离这些东西。我们想告诉你,C++不难用,也不复杂,它不是大多数开发者无法信任的语言。
【关于本书】
在本书中,我们列出了我们认为的最好的30条C++核心准则。通过详尽地解释这些准则,我们希望你至少能遵循这部分准则,哪怕你决定不去研究其他准则。我们选出的这部分准则不一定是最重要的,但它们一定能立即改善你的代码。当然,我们也希望你能意识到,还有很多其他的准则也应当遵循。我们希望你能阅读其余的准则,并在自己的代码中尝试。《C++核心准则》是写给各种水平的C++开发者的,本书也是如此。本书的内容并未按复杂程度递进,各章节也不必按某种顺序阅读。尽管有些章节可能明确引用了其他章节的内容,但各章节仍然是相互独立的。我们把每节的篇幅控制在3000字左右,因此你可能认为这是一本床头书而不是一本教科书。本书的目的不是教你学C++,而是就如何改进代码风格提出建议。
按照Kate在CppCon 2017上演讲的原始内容,我们将准则分为5章,每章有6节。在第1章“避重就轻不可取”[ 译注:原文是“Bikeshedding”,源于Northcote Parkinson的一段隐喻,下文有提及。隐喻中提到一个委员会在开会讨论财务预算时,花大量时间讨论建造自行车棚的项目,而对更复杂也更重要的核电厂项目却只花了很少的时间讨论。此处以成语“避重就轻”意译之。]中,我们提出了一些准则,方便你在一组特定的A和B选项中,轻松地决定何时选A而何时选B,尽可能减少无谓的争执,然后继续向前。“避重就轻”(Bikeshedding)[ 参阅网站exceptionnotfound上的文章“Bikeshedding—The Daily Software Anti-Pattern”。]源于C. Northcote Parkinson的“琐碎性定律”(law of triviality),即组织成员往往在讨论中过分关注一些琐碎的问题,比如更关注自行车棚要涂成什么颜色而不是与之毗邻的核电站的测试标准,虽然后者更重要,但对于前者,每个人都能说上两句。
在第2章“不要伤害自己”中,我们提出了在编写代码时防止“人身伤害”的准则。C++中残存的复杂性导致的问题之一是,在有些地方你很容易砸到自己的脚。例如,虽然以任意次序排列构造函数的初始化列表都是合法的,但随意排列绝非明智之举。
第3章名为“别再使用”,涉及C++中出于向后兼容而保留的内容,以及曾经有价值但因C++的发展而不再适用的建议。随着C++的发展,有些在当时看似不错的想法,我们发现其价值远低于最初的预期。标准化过程修正了这类问题,但你还是要了解它们,因为在面对遗留代码时,你还会遇到这类问题。C++保证了向后兼容——50年前用C语言写的代码今天应该还能编译。
第4章以“正确使用新特性”为题紧跟前一部分的内容。在使用概念(concept)、constexpr、结构式绑定(structured binding)等特性时需要格外注意。还是那句话,C++是不断发展的语言,每一个版本都会引入新特性,需要相应的教学内容来支持。尽管本书的目的不是教授C++20的新特性,但这些准则确实能让你体会到如何理解这些特性。
第5章的标题是“默认写出好代码”,里面讲的都是简单的准则,只要遵循它们就能写出好的代码,而不需要过多地考虑其他情况。这些准则将帮助你养成良好的习惯,而你写出的C++代码将易于理解并因此被他人欣赏。
正如一篇好文章一样,整本书的主题是逐渐浮现并展开的。发现准则背后的动机,并探索其更广泛的应用,这是我写这本书获得的乐趣,希望它也能转化为你阅读本书的乐趣之一。在适用的地方仔细观察时,你就会发现许多准则都是以不同的方式重申了软件工程的一些基本道理。提炼出这些道理,将大大改进你的编程实践。
我们真心希望大家喜欢本书并从中受益。