C++ / a working model

BOOK / SOURCE & READING RECORD

STL 源码剖析 / The Annotated STL Sources

侯捷;附录 C:孟岩

华中科技大学出版社,2002 年第一版,ISBN 7-5609-2699-1;研究副本为 534 页扫描,正文印刷页 1–494。

READING EVIDENCE / 已读完整正文

STL 源码剖析 / The Annotated STL Sources

实际逐页读取第 1–8 章、附录 A–C 与索引的文字(PDF 34–527,印刷页 1–494),并直接查看全部已识别的重要图示及代码疑点。第 1–6 章由分工阅读报告记录,第 7–8 章与附录由主阅读者完成;历史实现错误另作区分,不声称执行了书中全部代码。附录中的其他书籍推荐不等于那些书也已经读完。

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

Sources

从存储到对象,再到算法契约

第 2 章,印刷页 43–78;第 4 章 vector/list 构造与内存管理。

这本书把分配器放在容器之前,不是要求日常应用都手写内存池,而是让读者先分清存储、对象生存期与异常清理。取得一块足够大的内存,不表示其中已经存在可赋值的对象;构造中途失败时,又必须区分已经完成构造的部分与尚未使用的空间。这个区分随后贯穿 vector 的重分配、链表的节点创建和未初始化区间算法。今天阅读时应保留这条因果链,却不把旧实现的 8 字节分级、128 字节阈值或 POD 快速路径当成标准保证。现代对齐、隐式生存期规则、移动语义和 allocator_traits 都需要另行核对;看懂一份实现不等于得到所有实现的契约。

能力、表示和失效必须分别判断

第 3 章,印刷页 79–112;第 4 章;第 8 章 §8.3,印刷页 435–447。

迭代器让算法依赖操作能力,而不必知道容器怎样保存元素;traits 与标签分派则把能力差异转成不同实现路径。连续数组能用距离计算直接跳转,链表需要逐节点移动,分段 deque 又需要在缓冲区和索引表之间换算。它们提供相似表达式,却不拥有相同的复杂度与失效规则。阅读源码时尤其不能把“这个版本的 iterator 是指针”升级成可移植接口。输出配接器也不是已经存在的元素位置:向 back_inserter 赋值实际执行 push_back。相反,reserve 只准备容量,不会让空 vector 的 begin 成为合法输出目的。

历史实现需要与现代标准交叉阅读

第 6 章 §6.7;第 7 章,印刷页 413–424;第 8 章,印刷页 425–460。

本书保留了理解 SGI STL 的价值,也保留了旧接口与少量不准确表述。排序要求严格弱序,不要求所有相邻元素都满足比较器为真,重复键尤其能揭示这个区别。for_each 忽略返回值,却可以通过可写元素引用修改内容;把它笼统称为“不能修改元素”会误导读者。反向迭代器的 base 位于所指元素之后,end 和 rend 都不可解引用;书页中的危险输出不能成为运行保证。旧式 bind2nd、ptr_fun 和 mem_fun 今天可用 lambda、mem_fn 与 invoke 表达,但接口更新并不免除生命周期、输出空间与调用元数的责任。

相关基础课

迭代器:能力类别、范围与有效性算法:sort、边界查找与 erase-removeAllocator 与 pmr:资源选择和生命周期Lambda 捕获:闭包也是有生命期的对象

原创实践 →