Skip to content

手写实现专题 ​

手写题考察的是接口与不变量、生命周期、复杂度与失效规则、异常安全,而非算法技巧。 本专题覆盖五类高频手写题,每题给出「精简版(先交)与完整版」两档(各带实现范围说明、技术选型与自测小问答), 另附必需的配套实现;结构统一为「题面与澄清 → 接口与约束 → 精简版 → 完整版 → 配套 → 边界与测试 → 高频问答 → 常见错误」。代码均为可编译实现。

一、题目索引 ​

题目考察点难度关联讲解页
手写智能指针精简版:堆上独立控制块;完整版:类型擦除 + 同块分配 + weak_ptr::lock⭐⭐⭐⭐⭐智能指针
手写容器精简版:有序数组增删查;完整版:全接口;配套动态数组扩容⭐⭐⭐⭐vector、vector 扩容
手写 optional精简版 / 完整版均为 union 原地(区别在访问接口);配套指针版;含 ctor/dtor 时序题⭐⭐⭐⭐内存布局、RAII
手写 flat hashmap精简版:增删查 + 墓碑;完整版:全接口 + 迭代器⭐⭐⭐⭐unordered_map
手写并发件精简版:有界阻塞队列;完整版:SPSC 无锁环;配套:发布不可变快照⭐⭐⭐⭐并发编程

工程题(orderbook、带 get/put/get_at 的 snapshot store、LRU cache)不在本站,见本地练习仓 livecoding/tasks/(含评分器与 mutation 验证;flat_map 的手写评分器为其中的 t04_flat_map)。

二、通用答题步骤 ​

阶段时长内容
复述需求2 min复述要实现的对象与边界,澄清至少 3 个语义问题
写接口与约束5 min按下方七要素先落纸,再写第一行循环
主路径15 min写可编译可运行的最小实现,边写边讲
覆盖边界10 min空 / 单元素 / 满 / 重复 / 越界 / 删除后重插,并说明测试思路
收尾5 min报复杂度、已知限制、规模放大后的替代结构

接口与约束的七个要素

  1. 接口:函数签名、返回值、错误通道(异常 / optional / 布尔 / 错误码)
  2. 不变量:一句能写成 assert 的话(例:底层数组按 key 严格递增)
  3. 复杂度:逐操作;区分均摊与最坏
  4. 迭代器与引用失效规则
  5. 所有权与拷贝/移动语义(含是否 noexcept)
  6. 异常安全级别:基本保证 / 强保证 / 不抛,及达成手段
  7. 前置条件:违反即 UB(可 assert,不在热路径抛异常)

前七项回答「要满足什么」,技术选型回答「为什么这样实现」,两者分开写: 先给约束,再逐条给出设计与理由(见各题「技术选型」小节)。

三、跨题速查 ​

迭代器与引用失效 ​

容器插入删除
vector / flat_map扩容 → 全部失效;否则插入点及其后失效删除点及其后失效
deque两端插入:迭代器失效,引用/指针有效;中间插入全部失效中间删除全部失效;两端删除只失效被删的
list / map / set都不失效只失效被删元素
unordered_maprehash → 迭代器全部失效,引用/指针有效只失效被删元素
flat hashmaprehash → 全部失效(元素搬家)只失效被删元素

异常安全三档 ​

级别含义常用手段
基本保证不泄漏,不变量仍成立先分配/构造,成功后再改状态
强保证失败则状态原样copy-and-swap;先造新缓冲,成功再替换
不抛保证noexcept,失败即 terminate只做不会失败的操作;移动构造与析构标 noexcept

内存序档位 ​

场景内存序原因
仅自增计数,无跨变量顺序relaxed只需原子性
发布数据(写数据 → 写标志)release保证此前所有写在标志可见前完成
消费数据(读标志 → 读数据)acquire与 release 配对
无法判断 / 追求易推理seq_cst默认,代价最高

分配纪律 ​

  • reserve 是唯一能让容器提前停止分配的调用,也是唯一会让迭代器提前全部失效的调用;
  • 稳态零分配依赖对象池 / freelist / 侵入式链表 / 预分配;
  • 结论以分配计数(练习仓的 omtest::alloc_calls())或 perf stat 前后对比为准。

四、自测清单 ​

  • [ ] 写代码前先写接口与约束七要素,而不是先写循环
  • [ ] 能说出各容器迭代器失效规则,并给出失效原因
  • [ ] 能解释扩容时为何不能无条件 std::move(noexcept 与回滚)
  • [ ] 能徒手写出 union + placement new 的原地存储及四步流程
  • [ ] 能写出 weak_ptr::lock 的 CAS 循环并说明「先读后加」的竞态
  • [ ] 能解释 flat hashmap 墓碑的必要性,以及删除对引用失效的影响
  • [ ] 能说明 SPSC 环为何不需要 CAS、为何需要 alignas(64)
  • [ ] 每题都能给出规模放大后的第二版结构

五、与其他小类的关系 ​

六、子文档 ​

文件内容
smart-pointer.md配套 unique_ptr;shared_ptr 两档(精简版:堆上独立控制块 / 完整版:类型擦除 + 同块分配 + weak_ptr::lock);演进路径
container.mdFlatMap 两档(精简版增删查 / 完整版全接口 + 迭代器)与配套动态数组扩容
optional.mdoptional 两档(union 原地:最小接口 / 完整接口)+ 配套指针版,含 ctor/dtor 时序题
flat-hashmap.mdflat hashmap 两档(精简版增删查 / 完整版全接口 + 迭代器):开放寻址 + 墓碑 + rehash
concurrency.md两档(有界阻塞队列 / SPSC 无锁环)+ 配套单写多读快照发布

糌粑的面经笔记 · VitePress 版