C++ 语言实战(十三):面试总纲——30 题串起 13 章事故

系列收官。前十二章攒下 12 起事故、40 多个实测数字和一套完整的采集网关项目——这些东西最终要汇聚到一个场景里:面试。这章不讲故事了,做三件事:把网关项目整理成 3 分钟就能讲完的项目叙事;把 13 章的知识点收拢成 30 道高频题清单,每题一句话答点加出处;示范三道题的满分骨架。三十题每题都通向一段真实经历——这就是「项目驱动学习」的最后一块拼图。

一、先立论:面试官在买什么
把结论放在最前面:面试官买的不是知识点,是**「知识点在你的手里长什么样」**。背诵版答案是「虚函数通过虚表实现动态绑定」;你的版本是「ch04 我们靠它做了协议插件,vtable 两次间接寻址的热路径代价我们用 CRTP 绕开,代价是编译时间 +40%」。同一个知识点,后者带工程语境、带数字、带取舍——这是十二起事故换来的溢价。所以本章所有题目都标了出处章节:答案背了会忘,事故忘不掉。
二、3 分钟项目叙事:网关项目标准讲法
按 STAR 装配,数字全部来自前文,可直接誊进简历:
背景(30 秒):「我负责一个电芯产线的边缘采集网关,C++17 写的,对接 Modbus、OPC UA 和一家客户的私有协议,80 路通道、每秒 10 万采样点,交付在 ARM 边缘盒子上,跑了两年产线。」
冲突与动作(90 秒,挑两起讲深):推荐组合是 ch05 + ch06——「起过一次最重的事故:TCP 私有协议解析器按固定偏移取字段,粘包错位后 CRC 居然全过,温控指令写进了涂布机,400 米极片报废。我重写了增量状态机解析器,加随机切片 fuzz 10 万轮压到 0 幻觉帧;排查中还发现统计模块的 check-then-act 竞态,日报产量翻倍,用 TSan 抓现行后收敛进临界区。」时间够再加 ch07:「振动通道的锁争用用 40 行 SPSC 无锁环形缓冲解决,批量搬运从 8µs 降到 1.2µs。」
结果(30 秒):「吞吐从 3.8 万帧提升到 8.7 万,P99 从 47ms 收到 3.6ms,交付矩阵覆盖四种客户环境后兼容性零翻车。」——四个数字,每个背后都是一章。
三、30 题总纲:四组题单
语言与内存(9 题)
| # | 题目 | 一句话答点 | 出处 |
|---|---|---|---|
| 1 | 什么是 RAII | 资源生命周期绑定对象生命周期,异常安全免费获得 | ch02 |
| 2 | unique_ptr / shared_ptr 怎么选 | 独占用 unique,共享所有权才 shared;循环引用配 weak | ch02 |
| 3 | shared_ptr 为什么慢 | 控制块原子引用计数 + 两倍指针宽;热路径慎用拷贝 | ch02 |
| 4 | 什么是移动语义 | 把「拷贝」降级为「指针交接」,string 深拷贝事故是最好注脚 | ch03 |
| 5 | std::move 做了什么 | 只是类型转换(右值引用),不移动任何东西;移动发生在构造函数里 | ch03 |
| 6 | 什么是 RVO / 拷贝省略 | C++17 强制省略,按值返回不担心拷贝——先省略后 move | ch03 |
| 7 | 虚函数的实现机制 | vptr→vtable 两级间接,构造期不派发,丧失内联 | ch04 |
| 8 | sizeof 和内存对齐 | 成员对齐到自身大小、整体对齐到最大成员;序列化禁 memcpy | ch05 |
| 9 | placement new 与对象池 | 指定内存只构造;显式析构配对;池=复用定长热点对象 | ch11 |
并发与操作系统(8 题)
| # | 题目 | 一句话答点 | 出处 |
|---|---|---|---|
| 10 | 什么是数据竞争 | 两线程并发访问同一内存、至少一写、无同步=UB;TSan 按 happens-before 判定 | ch06 |
| 11 | mutex 和 atomic 怎么选 | atomic 管单变量读改写,mutex 管跨变量不变量;check-then-act 必须整体进临界区 | ch06 |
| 12 | 条件变量为什么有虚假唤醒 | 实现层允许无 notify 唤醒;谓词循环一并解决虚假唤醒与错过通知 | ch06 |
| 13 | 死锁四条件与避免 | 互斥/持有等待/不可剥夺/循环等待;锁排序 + scoped_lock + 持锁不调外部回调 | ch06 |
| 14 | 讲讲 acquire/release | release 写与 acquire 读配对建立 happens-before;SPSC 环形缓冲是标准例子 | ch07 |
| 15 | 什么是伪共享 | 不同变量同缓存行引发 MESI 乒乓;alignas(64) 隔离,实测差 3.7 倍 | ch07 |
| 16 | 什么是 ABA 问题 | CAS 值相等≠状态未变;版本号或 64 位单调索引;SPSC 无 CAS 天然免疫 | ch07 |
| 17 | 怎么保证低延迟 | mlockall+预热、绑核、SCHED_FIFO、关 THP——删掉延迟公式里所有不确定变量 | ch08 |
网络与协议(5 题)
| # | 题目 | 一句话答点 | 出处 |
|---|---|---|---|
| 18 | TCP 粘包是什么 | 流协议本无包,应用层定界三法:定长/分隔符/长度前缀 | ch05 |
| 19 | 帧解析器怎么设计 | 增量状态机五步:找头→len→攒齐→CRC→交付,半帧保留假头重同步 | ch05 |
| 20 | 大小端与网络序 | 协议写死大端,显式移位读写,禁 memcpy struct | ch05 |
| 21 | CRC 过了就可靠吗 | CRC 管内容不管边界;幻觉帧真实存在,防线分层(序号+ACK+三元校验) | ch05 |
| 22 | 长连接断线怎么处理 | 指数退避重连+风暴采样日志+序号去重,别让重连成为 DDoS | ch10 |
架构与交付(8 题)
| # | 题目 | 一句话答点 | 出处 |
|---|---|---|---|
| 23 | C++ 怎么做插件热加载 | dlopen+dlsym+C ABI 导出;谁导出谁回收;版本号协商 | ch04 |
| 24 | 异常穿越动态库会怎样 | 运行时多副本→RTTI 失配→catch 接不住→terminate;边界必换错误码 | ch10 |
| 25 | 异常和错误码怎么选 | 先问频率:高频预期内用错误码(0.6ns),罕见用异常(throw 2.8µs) | ch10 |
| 26 | noexcept 的陷阱 | 违反即 terminate;析构默认隐式 noexcept,析构内禁调可能抛的函数 | ch10 |
| 27 | 静态链接 vs 动态链接 | 确定性 vs 共享与更新;多 .so 运行时必须进程统一;musl 做真单文件 | ch12 |
| 28 | GLIBC 版本错误为什么发生 | 符号版本绑定构建环境 glibc=兼容下限;最老目标做构建环境 | ch12 |
| 29 | 性能问题怎么排查 | 工具箱:perf/strace/TSan/malloc_stats/core dump;先定性「CPU 在干什么」 | 全系列 |
| 30 | 零开销抽象怎么理解 | 运行时零开销≠零成本;编译时间与体积是税,代价要一起报 | ch09 |
四、三题满分示范
RAII(题 1):「RAII 把资源生命周期绑到对象生命周期上——构造获取、析构释放,栈展开时自动清理,异常安全是免费的。」升级动作:接事故——「我们在产线上为一条 RAII 纪律付过学费:网关 72 小时句柄泄漏打爆 fd 表,根因就是错误路径跳过了释放;修完之后 modbus C 句柄全部包进 unique_ptr 加自定义删除器。」再延伸:「所以代码评审里,裸 new、裸句柄、手动 lock 都是直接标红的。」定义→事故→纪律,60 秒完事。
内存序(题 14):先讲配对——「release 写与 acquire 读配对,acquire 读到新值就能看见对方之前的所有写,这是 happens-before。」再上代码级例子:「我们的 SPSC 环形缓冲里,写者先写数据槽再 release 发 tail,读者 acquire 读 tail 后才读槽——两句内存序就是『数据先于通知』协议。」最后亮工程观:「我们做过实验,全改 seq_cst 在 x86 加 9%、ARM 加 38%,全改 relaxed 在 x86 碰巧对、ARM 上乱序——所以纪律是每处 memory_order 必须说清配对,说不清就 seq_cst。」三层结构:机制→实例→纪律。
粘包(题 18):第一句纠偏就加分——「粘包不是 TCP 的 bug,字节流协议本无『包』,是应用层误按消息读流。」中段给方案:「应用层定界三种:定长、分隔符、长度前缀;二进制协议用魔数+len+CRC 的增量状态机,半帧保留、假头重同步。」收尾用数字:「事故版解析器随机切片 10 万轮产生 41 个幻觉帧,重写后 0,吞吐 86MB/s。」纠偏→方案→数据,这就是把事故讲成竞争力的样子。
五、工业经验怎么翻译给互联网面试官
很多读者拿这套经历去面互联网岗位,担心「产线」太远。不用改经历,改词汇映射:
| 工业语言 | 互联网等价表述 |
|---|---|
| 实时性、节拍超限 | 尾延迟、SLO 超限率 |
| 帧解析幻觉帧 | 协议健壮性、脏数据防线 |
| 插件热插拔 | 动态化架构、开闭原则落地 |
| 产量统计翻倍 | 数据一致性事故、幂等设计 |
| 交付矩阵翻车 | 多环境发布、构建体系 |
内核完全同构:都是「高吞吐数据管道 + 可靠性工程 + 尾延迟优化」。而工业背景的独有溢价——错误的代价是物理世界的报废品——反而让你对「为什么数据竞争是 UB」「为什么校验要分层」这类问题有一线工程师没有的切身答案。
六、收官:13 章学习路径
最后把全系列串成一条线。三章一批的推进节奏:ch01–04(起航)——为什么是 C++、RAII、移动语义、虚函数,语言的地基用事故夯实;ch05–07(协议与并发)——粘包状态机、线程池与互斥、SPSC 无锁,数据管道的三层 Armor;ch08–10(系统与健壮)——尾延迟、模板零开销、错误处理,从代码下潜到 OS 与 ABI;ch11–13(性能与交付)——内存池 ×2.3、交叉编译矩阵、面试总纲,把能力装订成作品。

十二起事故、三十道题、一个完整的网关——这个系列想证明的只有一件事:C++ 的每个「劝退知识点」,都是某个产线上真实燃烧过的事故现场;而把它们一一拆解归档的过程,就是工程师真正的成长路径。 下一门课,也许是无锁之外的并发世界,也许是把这套网关移植到 RISC-V——但那是另一个连载的事了。
