C++ / a working model

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

READING EVIDENCE / 已读完整正文

The Design and Evolution of C++

全部18章实质正文已实际阅读:第1章取自出版社英文样章印刷页19–25;第2–18章取自2002英文重印扫描,逐页连续覆盖PDF38–431(包括分部页,扫描省略的空白页不计正文)。远程OCR文字与代码逐段阅读,识别不全的代码、表格和继承/RTTI图以原图补核;末段PDF387–431直接读图。full指18章正文完成,不声称逐字校勘或读完书末参考文献、索引。该重印收入1995等后续补订,不冒充未经修订的1994首印;中译本未计入覆盖。

查看版本、实际阅读范围与原文入口 →

Sources

先列工程约束,再挑语言机制

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

原创实践 →