乐于分享
好东西不私藏

SGI STL 源码精华:从内存池到红黑树,我用 C++11 重新实现了一遍

SGI STL 源码精华:从内存池到红黑树,我用 C++11 重新实现了一遍

大家好,我是小康。

今天这篇文章,我想和你聊一件事。

你用过 std::vector,用过 std::map,用过 std::sort——

但你有没有想过一个问题:这些东西,我能自己写出来吗?

大部分人的答案是:不能

不是因为他们不够聪明,是因为没有人带他们走过这条路。

一、你以为自己懂 STL,但其实……

来,快问快答,回答不出来的说明你还不”懂”:

  • std::vector 扩容时,为什么是乘以 2,而不是加固定大小?加固定大小有什么问题?
  • std::list 的迭代器失效规则和 std::vector 为什么不一样?本质原因是什么?
  • std::map 底层是红黑树,红黑树插入时的旋转逻辑,你能手写出来吗?
  • std::sort 在小数组时会退化成插入排序,为什么?这个阈值是多少?
  • 分配器的一级分配器和二级分配器分别在什么场景下触发?二级分配器的内存池是怎么管理的?

这些问题,在面试里被问到的概率极高。

能把这五个问题流畅讲清楚的人,我见过的,不超过 10%

二、STL 源码真的很难看吗?

很多人翻开 SGI STL 的源码(大约有 2 万行),第一眼就放弃了。

template <class _Tpclass _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp)>classvector :protected _Vector_base<_Tp, _Alloc> {  ...typedef _Vector_base<_Tp, _Alloc> _Base;typedeftypename _Base::allocator_type allocator_type;  ...

模板嵌套模板,typedef 套 typedef,继承体系七拐八绕。

看不懂,正常。

但问题不在于 STL 源码难——而在于你是拿着”读懂”的心态去看,而不是拿着”写出来”的心态去做。

读源码,你是旁观者。写出来,你才是参与者。

这就是这门课和市面上所有 STL 课程最根本的区别:

我们不是带你读 SGI STL 源码,而是带你参考它的设计思想,从 0 开始写一遍。

三、课程大纲:5 个阶段,循序渐进

先看整体架构图

STL 的六大组件形成了一套完整的体系:分配器供给容器内存,迭代器作为容器和算法之间的桥梁,函数对象为算法注入策略,适配器在各层之间做转接。

这门课按照”由底向上,逐层累积“的方式推进。

第一阶段:内存基础——手写分配器(Allocator)

很多人觉得分配器没用,直接跳过。这是最大的坑。

分配器是 STL 的地基。SGI STL 为了对抗频繁小内存分配带来的内存碎片,设计了一级 + 二级双层分配器。二级分配器维护了一个 16 档的内存池(8 字节到 128 字节),通过 freelist 链表管理空闲块,避免反复调用 malloc

这一阶段你会实现:

  • __malloc_alloc_template(一级分配器):直接调用 malloc/free,处理 OOM 回调
  • __default_alloc_template(二级分配器):freelist 内存池完整实现
  • allocator 包装类:标准接口封装
  • uninitialized_copy / uninitialized_fill:内存上的对象构造原语

学完你能回答:为什么 STL 的小对象分配比裸 new 快?freelist 的内存是怎么归还的?

第二阶段:迭代器与 traits 萃取

迭代器是 STL 里最精妙的设计之一,也是很多人理解断层的地方。

为什么需要 iterator_traits

因为原生指针(int*)也是迭代器,但指针没有成员类型。iterator_traits 用模板偏特化打了一个补丁,让算法能用同一套代码处理类迭代器对象原生指针

这一阶段你会实现:

  • 5 种迭代器类型标签(input_iterator_tag 等)
  • iterator_traits 完整实现,包含对原生指针和 const 指针的偏特化
  • advance / distance 的多版本分发(针对不同迭代器类型走不同路径)
  • 迭代器适配器:reverse_iterator 完整实现

学完你能回答:为什么 reverse_iterator 的 operator* 要先退一步再解引用?iterator_traits 没有它会发生什么?

第三阶段:核心容器实现

这是课程体量最大的阶段,也是最有成就感的阶段。

每实现一个容器,你都会深刻理解它的内部结构,以及为什么”这样设计”。

3.1 vector

  • 三指针结构(start / finish / end_of_storage
  • push_back 扩容全流程:新容量计算 → 旧元素搬移 → 析构旧空间
  • 迭代器失效的根本原因(扩容导致地址变更)
  • emplace_back vs push_back(C++11 起的差异)

3.2 list

  • 带哨兵节点的环状双向链表设计
  • 迭代器的 ++/-- 实现细节
  • splice / sort(链表原地归并排序,不移动数据,只改指针)
  • 为什么 list 迭代器不会因插入而失效

3.3 deque

  • 分段连续内存的 map + buffer 结构(这是 STL 里最复杂的容器)
  • iterator 如何跨越 buffer 边界
  • push_front 和 push_back 的非对称扩容策略

3.4 stack 和 queue

  • 基于 deque 的适配器实现,代码很短但思想很清晰
  • 理解”适配器模式”在 STL 中的实际运用

3.5 heap 与 priority_queue

  • push_heap / pop_heap / make_heap / sort_heap 完整实现
  • 大顶堆的下沉和上浮过程
  • priority_queue 基于堆的封装

3.6 RB-tree(红黑树,重头戏)

  • 红黑树的五条性质和它背后的设计直觉
  • 左旋 / 右旋操作
  • 插入修复:3 种 case 的判断和处理
  • 删除修复:4 种 case(最难的部分,逐步拆解)
  • iterator 的中序遍历实现

3.7 map / set / multimap / multiset

  • 基于 RB-tree 的薄包装层
  • map::operator[] 的”插入语义”细节
  • equal_range 的实现原理

3.8 hashtable / hash_map / hash_set

  • 开链法(separate chaining)哈希表实现
  • 素数桶数组的扩容策略
  • 冲突处理和负载因子控制

第四阶段:核心算法实现

算法部分只实现高频核心算法,不贪多。

  • find / find_if:线性查找,理解迭代器抽象的价值
  • copy / fill:针对 trivially_copyable 类型的 memmove 优化路径(__type_traits 萃取)
  • sort:完整实现 introsort(快排 + 堆排 + 插入排序三合一)——这是 std::sort 的真实算法,面试高频
  • merge / inplace_merge:归并操作
  • lower_bound / upper_bound / binary_search:二分系列
  • next_permutation / prev_permutation:全排列生成

第五阶段:函数对象与适配器

最后一个阶段,也是”让 STL 真正活起来”的阶段。

  • 基本函数对象:less / greater / plus / minus / negate 等
  • bind1st / bind2nd(C++98 风格的参数绑定)
  • 函数适配器:not1 / not2
  • ptr_fun:将普通函数包装成函数对象
  • 全部用 C++11 的 operator() 方式重新实现,对比 C++98 版本的繁琐,理解现代 C++ 的进步

四、为什么用 C++11 而不是 C++98?

SGI STL 原版是 C++98 写的,有大量历史包袱:手动 typedef、满屏宏定义、没有 auto 和 nullptr……

用 C++98 还原 STL,你学到的是历史,不是工程能力。

这门课用 C++11 实现——保留 STL 的核心设计思想,但用现代 C++ 的语法表达。你会写出可读性更高、更接近实际工作代码的版本,对比之下也更能理解 C++11 为什么这样改。

五、学完能获得什么?

✅ 彻底搞懂为什么“,而不只是”是什么”——容器选型、迭代器失效、算法复杂度,你有自己的判断依据,不再死背结论

✅ 一个能写进简历的硬核项目——手写 STL 核心组件,比”熟悉 C++ STL”这句话有说服力一百倍

✅ 面试底气——红黑树、内存池、迭代器萃取,被问到直接展开讲,不虚

✅ 真实理解模板与泛型编程——STL 是 C++ 模板最集中的教材,写完这个项目,你对模板的理解会上一个台阶

✅ 为后续深入打好基础——理解了 STL,再去看 Boost、EASTL、或者自己设计数据结构,都会顺很多

六、适合哪些人?

✔️ 对 STL 源码好奇,想知道底层怎么实现的开发者

✔️ 简历上 C++ 项目太少,想加一个有含金量的项目

✔️ 即将面试,想把 STL 相关知识彻底搞扎实

✔️ 工作中用 C++ 但感觉只停留在会用的层次,想往深了走的工程师

需要的基础:会 C++ 基础语法,了解类、模板、指针。不需要提前看过 STL 源码。

七、关于定价

说实话,这门课的制作工作量非常大。

五个阶段、从分配器到红黑树再到 introsort,每个模块我都要:确定增量式的实现路径,确保每一步都能编译跑通,解释每一个设计决策背后的原因。

预售价:799 元

课程制作完毕后恢复原价:999 元。

现在报名是最划算的窗口期!!课程内容我争取 4 月 8 日制作完毕。

特别说明:预售阶段定价低,是因为你选择了在内容还没全部到位的时候信任我——作为回报,你锁定了最低价格,并且会跟着课程进度一起走,第一时间拿到每一节新内容。

报名后你还能获得

  • 全部课程资料(含各阶段完整项目源码,可直接运行)
  • 专属学习微信群,遇到问题随时提问
  • 代码审核服务,小康帮你看代码、指出问题
  • 学习进度跟踪,确保你真的学会、不掉队

八、报名方式

扫码添加小康微信,备注「 STL 」,微信 / 支付宝付款 799 元即可。

九、还没有 C/C++ 基础?从这里开始

学 STL 实战需要 C++ 基础。如果你还没有系统学过,可以先了解我的入门课程体系:

C 语言快速入门课(299 元)——从零开始,项目驱动,几天时间建立扎实的 C 语言基础,不绕弯路。

C++ 快速入门课(299 元)——从 C 到 C++,类、模板、STL 使用,一路打通,学完就能上手 STL 实战课。

Linux 编程入门课(399 元)——文件 IO、多进程、多线程、网络编程,10 节课 9 个实战项目,和 C/C++ 入门课是同一套体系。

三门打包价 899 元,比单买省近 100 元,是系统入门 C/C++ 最划算的路径。

如果你已经有 C++ 基础,STL 课学完了想继续往深处走,可以看看我的 C++ 硬核项目实战课程系列为什么同样是”学过C++”,有人面试碾压,有人开口就怂?差距在这18个C++硬核项目

另外, 最近小康开放了一个新的 C++ 项目实战课程:参考 LevelDB 实现的 LSM 存储项目 StoneDB,涵盖 MemTable / SSTable、WAL 日志、Compaction、多级存储等核心机制,完整还原 KV 存储引擎设计。感兴趣的朋友可以看看 👉 课程详情手写 C++ LSM存储引擎:MemTable、SSTable、Compaction 全流程实现

最后说一句

能读懂别人代码和能自己写出来,是两个完全不同的段位。

STL 这套东西设计了几十年,经历了无数工程考验。把它从 0 写一遍,不只是学了一个项目——你是在和设计它的那些人,进行一次跨越时间的对话。

我是小康,我们课程里见。

💬 你最想搞懂 STL 的哪个部分?欢迎评论区留言——红黑树?内存池?还是迭代器萃取?

P.S. 如果你之前报过我的其他课程,知道我的风格:增量式实现、每步都跑通、不灌水。这门 STL 课,同样如此。