C++之美:代码整洁、安全又跑得快的30个要诀(英文版)
  • 推荐0
  • 收藏0
  • 浏览195

C++之美:代码整洁、安全又跑得快的30个要诀(英文版)

【美】J. 盖伊·戴维森 , 【美】凯特·格雷戈里 (作者)  符隆美 (责任编辑)

  • 书  号:9787121446009
  • 出版日期:2024-05-01
  • 页  数:332
  • 开  本:16(240*190)
  • 出版状态:上市销售
  • 维护人:博文小编
《C++之美:代码整洁、安全又跑得快的30个要诀(英文版)》从《C++核心准则》(C++ Core Guideline)数百个条目中精心挑选了30条准则进行细致、深入的讲解。内容涵盖C++语言最主要的方面,如类型系统、面向对象、模板和元编程、错误处理、程序性能、常量性等,其间又恰如其分地穿插了编码风格、设计模式等主题。探讨的过程中处处可见来自作者数十年职业生涯的经验和示例,除了深入的洞察,行文中充满了趣味性。
作者试图通过这种突出重点、以点带面的方式帮助读者了解并学习C++核心准则,进而更深入地掌握C++这门编程语言,特别是它的“现代”形态。
让你的代码立即向着好的方向改变
J. 盖伊·戴维森于1980年通过Acorn Atom 首次接触到计算机。他青少年时期的大部分时间都是在各种家用电脑上编写游戏,这些电脑包括Sinclair Research ZX81和ZX Spectrum,以及Atari ST。后来他从苏塞克斯大学获得了数学学位,他还涉足过戏剧,在一支灵魂乐队中弹奏过键盘,之后在20世纪90年代初,他决定编写演示程序,并于1997年开始在Codemasters的伦敦办公室工作,从此进入游戏行业。
1999年,他加入了Creative Assembly,现在是那里的工程实践主管。他从事《全面战争》系列游戏的工作,管理着早期的游戏目录,也负责在工程团队中提升编程水准。他在IGGI咨询委员会、BSI C++小组和ISO C++委员会中任职。他是ACCU委员会的标准官员,并在ACCU会议的编程委员会任职。他是#include discord服务器的管理员。他担任多个组织的行为准则负责人。他会在C++会议和各种聚会上发言,特别是活跃于将线性代数添加到标准库的相关议题中。
在丰富的业余时间里,他通过Prospela和BAME in Games提供C++辅导;通过UKIE、STEMNet 及作为电子游戏大使(Video Game Ambassador)在学校、学院和大学发表演讲;练习并教授吴式太极拳 ;学习钢琴;在布莱顿节日合唱团唱男低音部;经营当地的一个电影俱乐部;是BAFTA的投票成员;代表英格兰和威尔士绿党两次参加地方议会选举(未获成功);正在尝试学习西班牙语。偶尔你会发现他在牌桌上打一个点1便士的桥牌。可能还有其他事情:他是个闲不住的人。

凯特·格雷戈里从接触编程、结识几位最亲密的朋友到认识她的丈夫,都是1977年在滑铁卢大学完成的,所有这些她从未想过回头。她的专业是化学工程,这正说明你很难从一个人的专业中看出什么。她在安大略省农村的地下室有一个小房间,里面放着一些古老的计算机:PET、C64、手工焊接的6502系统等,她把这些作为一个更单纯时代的纪念品。1986年以来,她与丈夫一起经营Gregory咨询公司,帮助世界各地的客户更好地完成工作。
凯特曾在五大洲都做过主题演讲,偏爱发掘一些改变认知的真相,然后与人分享,此外还投入大量的时间在各种 C++活动中做志愿者。其中#include 是她的最爱,此社区正在改变这个行业,使其更受欢迎也更具包容性。他们的Discord服务器是一处温馨的场所,在这里你可以作为初学者学习 C++,也可以参与WG21的文章创作工作以改变我们使用的语言,或者做任何介于两者之间的事情。
她会远离键盘,享受和孙辈的时光、安大略的湖泊和露营地、独木舟的桨、林间的薄雾和世界各地机场的诱惑。她是美食家、桌游玩家,也是一个忍不住要主动提供帮助的人,线下的她和线上一样活跃,只是不那么引人注意。自2016年从四期黑色素瘤中幸存下来,她就不再那么在意别人的想法和期望了,而更加在意自己以后想要什么。这样很好。
前言
编写C++代码的复杂性随着每一版新标准的到来及每一种新教程的出现而逐渐降低。会议、博客和图书比比皆是,这是好事。世界上并没有足够多的高素质工程师来解决我们正面临的现实问题。
尽管语言不断简化,但就如何编写良好的 C++代码,仍有很多地方需要学习。C++的发明者Bjarne Stroustrup和维护C++的标准机构的召集人Herb Sutter投入了大量资源来创作便于学习C++和编写更好C++代码的教学资料。这些资料包括The C++ Programming Language 、A Tour of C++ ,以及Exceptional C++ 和C++ Coding Standards 。
书的问题在于它代表了事物状态的一种时间快照,本书也一样,然而C++是一门不断发展的语言。1998年的好建议放在现在或许不再是多么聪明的主意。不断发展的语言需要不断发现的准则。
在2015年的CppCon大会上,Bjarne Stroustrup和Herb Sutter在他们的两个主题 , 演讲中推出了一项在线资源——《C++核心准则》 。准则为改善 C++代码风格提供了出色又简单的建议,遵循这些建议,便可以从一开始就写出正确且高效的代码。它是 C++从业者所需的持续发展的指南,作者将很乐意审阅提出修正或改进的拉取请求(pull request)。从初学者到老手,每个人都应该遵循这些建议。
准则为改善C++代码风格提供了出色又简单的建议,遵循这些建议,便可以从一开始就写出正确且高效的代码。
2020年2月底,在#include discord 上,凯特·格雷戈里“推销”了自己针对核心准则写一本书的兴趣,我小心翼翼地抓住了这个机会。凯特在2017年的CppCon大会 上做了一次演讲,其中只提到了《C++核心准则》中的10条。我和她一样,对推动更好的程序设计充满热情。我是英国历史最悠久、规模最大的游戏开发工作室Creative Assembly的工程实践主管,在过去20多年里,我花了很多时间帮助我们优秀的工程师变得更卓越。据我们观察,尽管《C++核心准则》简单易懂,但很多开发者却不是特别熟悉。我们想推动准则的普及,于是决定写这本书,因为当前关于准则的资料还不够多。
《C++核心准则》可以通过链接[2]访问。优秀的建议完全堆在一起,事实上,让人难以知晓从哪里开始。从头到尾地阅读是可行的,但需要反复阅读,否则很难掌握一整套内容。它们包括接口、函数、并发等22个主要部分。每个部分都是由一条条准则组成的,有的部分包含几条,有的部分包含几十条。准则使用主要部分的字母加上它在该部分中的编号来标识,中间用点号隔开。例如,“F.3:保持函数简短”是F部分“函数”中的第3条准则。
每条准则都以类似的方式编排。首先是准则的标题,用一种动作来表述(这样做、不这样做、避免这样做或者建议这样做),然后提供理由和一些示例,可能还包含准则的例外情况。最后还有一条如何实施这条准则的说明。说明的内容多种多样,有给静态分析工具作者的建议,也有如何进行代码审阅的提示。事实上阅读这些准则是有技巧的;决定在自己的代码中优先考虑哪些准则是一个个人发现(personal discovery)问题 。让我们来告诉你如何开始利用核心准则的智慧吧。
C++中有一些尖锐的边缘,也有一些积灰的角落,它们在现代 C++中不常使用。我们想让大家远离这些。我们想告诉你,C++不一定是难用的、复杂的,或者让大多数开发者无法信任的。
关于本书
本书提供了我们认为最好的30条C++核心准则。通过详尽地解释这些准则,我们希望大家至少遵守这些准则,哪怕你决定不去研究其余准则。我们选出的这些准则不一定是最重要的。然而,它们一定是能让你的代码立即向着好的方向改变的那些准则。当然,我们希望你能同时意识到其他的许多好准则也可以遵循。我们希望你能阅读其余准则,并在自己的代码中尝试使用它们。正如《C++核心准则》针对的是各种经验水平的C++开发者,本书针对的读者人群也是一样的。本书的内容并不是按复杂程度递进的,各章节也不必按一定的顺序阅读。尽管可能明确引用其他章节,但各章节仍相互独立。我们控制了每节的篇幅,因此你可能认为这是一本床头书而不是一本教科书。本书的目的不是教你C++,而是就如何改进代码风格提出建议。
按照凯特在2017年CppCon上的原始演讲,我们将准则分为5章,每章6节。在第1章“避重就轻 不可取”(Bikeshedding is bad)中,我们提出了一些准则,方便你在一组特定的A和B选项中,轻松地决定何时做A或者B,将无谓的争执降至最少,然后继续向前。“避重就轻”(bikeshedding) 源于C. Northcote Parkinson的“琐碎性定律”(law of triviality),即相对于重要的问题,比如核电站的测试标准,组织成员通常将过多的精力不成比例地投入琐碎问题,比如将自行车棚涂成什么颜色,因为后者每个人都懂一点。
在第2章“不要伤害自己”(Don’t hurt yourself)中,我们提出了在编写代码时防止“人身伤害”的准则。C++中残存的复杂性导致的问题之一是,在有些地方你很容易砸到自己的脚。例如,虽然以任意次序排列构造函数的初始化列表都合法,但随意排列却极不明智。
第3章名为“别再使用”(Stop using that),涉及语言中出于向后兼容而保留的部分,以及曾经有价值但随着语言的发展被取代的建议。随着C++的发展,有些东西之前看来是个好主意,后来可能发现其价值远低于最初的预期。标准化过程修正了这类问题,但大家还是要了解,因为在面对遗留代码时,你还会遇到其中的例子。C++保证了向后兼容:50年前用C语言编写的代码今天应当仍可编译。
第4章以“正确使用新特性”(Use this new thing properly)为题紧跟前一章。使用概念(concept)、constexpr、结构式绑定(structured binding)等特性时需要注意。还是那句话,C++是不断发展的标准,每一版都会带来新特性,需要相应的教学内容来支持。尽管本书的目的不是教你C++ 20的新特性,但这些准则确实能让你体会一下如何理解这些特性。
最后第5章的标题是“默认写出好代码”(Write code well by default)。其中介绍的都是简单的准则,只要遵循就能写出好的代码,而不需要过多考虑。这将带来体现良好习惯的C++代码,被你的同事所理解和欣赏。
与任何好的文本一样,整本书中都会出现并发展一些主题。写作本书的部分乐趣,我希望也能转化为阅读本书的乐趣之一,即看到这些准则背后的动机,并审视其更广泛的应用。许多准则,在适用的地方仔细观察时,都是以不同的方式重申了软件工程的一些基本的道理。提取这些道理将大大改善你的编码实践。
我们真心希望大家喜欢本书并从中受益。
访问代码
所有的代码都可以从Compiler Explorer网站上访问。Matt Godbolt贴心地为每一节保留了可稳定访问的链接,把https://******.org/z/cg30-ch(链接[3])和节号连起来即可。例如,https://******.org/z/cg30-ch1.3会带你看到1.3节的完整代码。我们建议你从https:// ******. org/z/cg30-ch0.0(链接[4])开始,查看如何使用网站和代码的说明。

盖伊·戴维森 @hatcat01 hatcat.com
凯特·格雷戈里 @gregcons gregcons.com
2021年10月

致谢
2020年和2021年是不平静的两年,我们要感谢许多人在本书写作出版过程中提供的支持,包括主动提供的和碰巧提供的。
我们当然要感谢Bjarne Stroustrup和Herb Sutter,是他们带来了这份《C++核心准则》,并鼓励我们撰写与之相关的内容。我们也要感谢CppCon的与会者作为听众探索了本书的部分内容。
在有几分孤寂的写作过程中,我们的家人提供了至关重要的支持,没有他们,完成这项工作还要困难得多。
自2017年7月以来,来自includecpp.org站点的#include discord朋友团在我们日常钻研C++的生活中持续地提供支持。 我们将拿出本书收入的十分之一捐赠给他们。所有的朋友,请接受我们鞠躬致谢。
维护标准的机构ISO WG21 C++委员会的一些成员向我们提供了帮助。我们要感谢Michael Wong和Tony van Eerd,感谢他们的见解。
本书所有的代码示例都可以从Compiler Explorer 站点通过可稳定访问且可辨识的链接获取,这得益于Matt Godbolt的慷慨付出,他是这项优质服务的创建者。在我们的感激之外,我们还想告知他C++社区已经从他的努力中获益良多。
在本书各章最初的准备过程中,cppreference.com 是极好的研究工具,因此我们要感谢站点的创建人和主持者Nate Kohl、管理员Povilas Kanapickas和Sergey Zubkov,以及Tim Song和所有其他贡献者的持续努力,感谢他们维护这一优质资源。他们是社区的英雄。
在写完3.6节后,我们发现相当多的灵感来自Arthur O’Dwyer的一篇文章。非常感谢他对社区的持续服务。他的博客 还包含他努力发掘的20世纪70、80年代一些最早的基于计算机的文本冒险游戏的故事。
这样的一本书需要一支审校大军,因此我们向Bjarne Stroustrup、Roger Orr、Clare Macrae、Arthur O’Dwyer、Ivan Čukić、Rainer Grimm和Matt Godbolt表示感谢。
Addison-Wesley的团队也提供了巨大的帮助,为此我们非常感谢Gregory Doench、Audrey Doyle、Aswini Kumar、Menka Mehta、Julie Nahil和Mark Taber。

目录

第1章 避重就轻不可取 21
1.1 P.2:使用ISO C++标准编写代码 23
1.2 F.51:有选择时优先使用默认参数而非重载 33
1.3 C.45:不要定义仅初始化数据成员的默认构造函数,
而应使用类成员初始化 43
1.4 C.131:避免平凡的get和set函数 51
1.5 ES.10:每条语句只声明一个名字 61
1.6 NR.2:不强求函数只用一条return语句 69
第2章 不要伤害自己 79
2.1 P.11:将凌乱的结构封装起来,而不是使其散布于代码中 81
2.2 I.23:尽量减少函数参数 91
2.3 I.26:使用C风格子集获取跨编译器的ABI 99
2.4 C.47:按成员声明顺序定义并初始化成员变量 107
2.5 CP.3:尽量减少可写数据的显式共享 117
2.6 T.120:只在真正需要时使用模板元编程 127
第3章 别再使用 139
3.1 I.11:切勿通过原生指针(T*)或引用(T&)转移所有权 141
3.2 I.3:避免使用单例 149
3.3 C.90:依靠构造函数和赋值运算符,而不是memset和memcpy 159
3.4 ES.50:不要用强制转换去除const限定符 169
3.5 E.28:避免基于全局状态(如errno)的错误处理 179
3.6 SF.7:不要在头文件的全局作用域写using namespace 189

第4章 正确使用新特性 199
4.1 F.21:优先选择结构体或元组返回多个“输出”值 201
4.2 Enum.3:优先选择类枚举而不是“普通”枚举 213
4.3 ES.5:保持作用域小 221
4.4 Con.5:使用constexpr表示编译时可以计算的值 233
4.5 T.1:使用模板提高代码的抽象层次 245
4.6 T.10:为所有模板参数指定概念 255
第5章 默认写出好代码 265
5.1 P.4:理想情况下,程序应具有静态类型安全性 267
5.2 P.10:优先选择不可变数据而不是可变数据 279
5.3 I.30:封装违反规则的部分 287
5.4 ES.22:确定初始值后再声明变量 295
5.5 Per.7:为促成优化而设计 305
5.6 E.6:使用RAII防止泄露 313
后记 325
跋 327

读者评论