BOOK / SOURCE & READING RECORD
The Design and Evolution of C++
Bjarne Stroustrup
1994 work, official publisher sample; 2002 China Machine Press English reprint ISBN 7-111-09592-8, 466-page scan incorporating later-printing corrections including 1995 explicit constructors
The Design and Evolution of C++
全部18章实质正文已实际阅读:第1章取自出版社英文样章印刷页19–25;第2–18章取自2002英文重印扫描,逐页连续覆盖PDF38–431(包括分部页,扫描省略的空白页不计正文)。远程OCR文字与代码逐段阅读,识别不全的代码、表格和继承/RTTI图以原图补核;末段PDF387–431直接读图。full指18章正文完成,不声称逐字校勘或读完书末参考文献、索引。该重印收入1995等后续补订,不冒充未经修订的1994首印;中译本未计入覆盖。
查看版本、实际阅读范围与原文入口 →Sources
Public English reprint scan — privately researched
466页图像扫描,版权页确认2002年机械工业出版社英文重印;第2–18章实质正文、代码及图表已完整阅读,精确章页范围另存私有证据。书末参考文献与索引未计入full正文覆盖。
研究副本不在本站公开链接。
- Pearson English sample PDF — Chapter 1
第1章印刷页19–25全部;读者说明页1–7;目录核对全书18章。出版社页面样章链接多一个空格,去掉空格后可读。
- Author's D&E page
作者说明、前言和读者说明入口,不提供英文全书。
- InformIT first-edition record
核对1994年第1版及样章范围;购买后的电子书未访问。
先列工程约束,再挑语言机制
Chapter 1 §§1.1–1.3, printed pp.19–25; publisher sample PDF pp.30–36
第1章的关键不是宣判某一种语言胜出,而是将可理解的模型、可接受的运行成本、独立编译和跨环境实现同时放进设计问题。能清楚表达概念的工具若无法完成实际计算,仍然不合用;跑得快却让类型错误长期潜伏的工具也要支付维护代价。迁移到今天的做法,是先写出领域对象必须保持的不变量,再决定是否需要继承、动态分配或模板。一个只有两个整数的值类型也能承担真正的抽象:它让有效状态比调用者的自觉更可靠。作者当年对具体实现的性能观察属于历史证据,不是现代语言或编译器的永久排名。
零开销不是所有抽象都免费
Chapter 4 §§4.2–4.6, printed pp.110–122; English scan PDF pp.121–133
第4章的零开销规则针对一种容易被忽略的成本:为了支持少数高级功能,让每个对象、每次访问都承担额外负担。它不承诺任何程序一旦使用抽象就自动更快,也不否认实现可以为其他目标作取舍。书中同时要求功能能够实现、能够教会用户,并能与独立开发的组件组合;单独把某一条原则推到极端,反而会失去平衡。应用到代码评审,应分别问未使用者是否付费、实际使用路径做了什么工作、是否保留了必要控制,而不是凭语法长短判断效率。语言标准通常规定行为,不承诺固定布局或机器指令;成本仍需在目标环境中测量。
可移植性来自明确边界,不来自侥幸通过编译
Chapter 6 §§6.1–6.1.1, pp.133–135; §6.3.2, pp.143–146; scan PDF pp.143–145,153–156
第6章把标准看成程序员与实现者之间的约定,同时指出约定不会包办对象布局、调试格式或整个操作系统环境。临时对象生命周期的讨论进一步表明,把规则留得模糊并不会给用户真正的自由:不同实现作不同选择后,可移植程序反而只能依赖最苛刻的交集。今天设计接口也一样,拥有对象与借用对象的寿命必须说清;一个指针能通过类型检查,不代表它指向的存储仍有效。书中关于负数余数、隐式int和三字符序列的描述属于历史规则,不能作为C++20规范;值得保留的是区分保证、实现差异和接口前提的思考方式。
先设计可组合的库,再争论语言特性
Chapter 8 §§8.1–8.2.3, pp.181–184, §8.5 p.194; Chapter 9 §9.2.3 p.200; scan PDF pp.190–193,203,209
第8章把独立开发的库能否共同工作放在设计中心:名字冲突、错误传播、资源管理与类型信息,都可能让两个分别正确的组件无法拼在一起。多一个语言特性不等于解决全部集成问题,两个都声称覆盖整个世界的基础类库尤其容易互相挤压。实际设计应先明确重编译成本、用户扩展方式、是否跨语言调用等约束,再决定使用值类型、模板或抽象接口。第9章反省早期基础库不足,说明重复造轮子还会把初学者过早推向复杂实现细节。现代教学宜先学会使用标准容器与资源管理类型,再研究实现;这不妨碍需要时继续深入底层。
错误通知与资源善后,是两份不同的责任
Chapter 16 §§16.4–16.5, printed pp.386–390, §§16.9–16.9.1 pp.395–397; scan PDF pp.392–396,401–403
第16章把库发现失败和上层决定如何处理失败分开,说明异常的意义不是替程序自动修复错误,而是允许信息跨过暂时无法处理它的层。清理资源则要依靠另一个契约:资源由对象拥有,已构造对象离开作用域时执行清理。把每一次分配都配一个手写catch再释放,看似谨慎,却让正常路径与清理逻辑互相缠绕,也容易遗漏第二个失败点。现代代码可用标准RAII类型承接这一思想,但不能把旧throw类型列表、unexpected或历史坏分配名字当成C++20接口。书中为不抛异常路径设计的表驱动方案是实现策略,也不等于所有异常处理在任何环境中都没有时间或空间成本。
替换机制之前,先解释它承担的工作
Chapter 18 §18.1, printed pp.423–426; English reprint scan PDF pp.428–431
第18章没有停在宏不安全这一句口号,而是把预处理器承担的任务拆开:符号常量、类型泛化、源文件组合、条件选择和实现控制并不是同一个问题。某些任务可以交给有作用域、有类型的语言机制,另一些不能只靠普通if替换,因为不执行的分支仍需通过语法与类型检查。迁移旧代码时,先认出宏解决的具体问题,再选替代物,比一次性宣布禁用更可靠。书中设想的include关键字并非当时已接受特性;今天的constexpr、if constexpr与模块也各有适用边界,不能把后来出现的机制倒写成1994年的事实。
相关基础课
封装、继承与组合:OOP 的边界访问控制 Access control 与继承权限explicit:把转换意图留在调用处从源文件到程序:Compilation 与 Linking