Browse Source

ingest: 面试八股第四批学习记录(僵尸孤儿守护/TCP可靠/struct-vs-class/构造析构/SMP多核)+ 第四批复习总结

OpenCode 2 weeks ago
parent
commit
54ecb4500b

+ 74 - 0
X-Knowledge-Base/raw/面试八股/42.僵尸-孤儿-守护进程.md

@@ -0,0 +1,74 @@
+## 僵尸/孤儿/守护进程
+
+## 判别规则(核心,唯一要记的)
+
+1. **看"谁死了 + 谁收尸"**:子进程已退出、父进程还活着且**没 wait 回收** → **僵尸**;父进程已 `wait` → 不是(已回收)
+2. **看"父先死 + 子还活"**:父进程先退出、子进程还活着 → **孤儿**(被 init 收养继续跑)
+3. **看"是否脱离终端"**:主动 `setsid()` 脱离终端、后台运行、无控制终端 → **守护进程**;还连着终端 → 不是
+
+一句话:**"僵尸是子死了没人收尸,孤儿是父先死了孩子被 init 收养,守护是主动脱离终端独立后台跑。"**
+
+## 抽象描述(一句话本质)
+
+三者本质是**进程与父进程关系**的不同状态:僵尸=子死未收尸;孤儿=父先死子被收养;守护=主动脱离终端后台运行。
+
+## 易混对比
+
+| | 僵尸 Zombie | 孤儿 Orphan | 守护 Daemon |
+|---|---|---|---|
+| 谁死了 | 子进程死,父活着 | 父死,子活着 | 都没死 |
+| 状态本质 | 子进程残留 PCB 未被回收 | 子进程被 init 收养继续运行 | 主动脱离终端后台运行 |
+| 谁管它 | 等父进程 wait 回收 | init 收养 | 自己独立 |
+| 危害 | 占 PCB,父不回收会泄漏 | 无害 | 无害 |
+| 是否"死了" | 子已死 | 父已死 | 谁都没死 |
+
+## 僵尸进程三个解法
+
+| 方法 | 原理 | 适用场景 |
+|------|------|---------|
+| 父进程 wait()/waitpid() | 父主动回收子进程状态信息 | 父进程有子进程生命周期管理 |
+| 双 fork | 子 fork 孙,自己立刻退出,孙变孤儿被 init 自动回收 | 父进程不想管子进程回收 |
+| signal(SIGCHLD, SIG_IGN) | 告诉内核忽略退出状态,内核自动回收 | 父进程不关心子进程退出 |
+
+## 守护进程创建步骤(标准流程)
+
+1. `fork()` → 子进程,父进程退出(脱离终端控制)
+2. `setsid()` → 创建新会话,成为 session leader,脱离控制终端
+3. `fork()` → 再 fork 一次,孙子进程运行,父进程退出(确保不是 session leader,防止重新获取终端)
+4. `chdir("/")` → 改工作目录,防止占用可卸载的文件系统
+5. `umask(0)` → 重置文件权限掩码
+6. `close(0/1/2)` → 关闭标准输入输出,重定向到 `/dev/null`
+
+**两个 fork 的目的**:第一次 fork + setsid 让进程成为会话 leader 脱离终端;第二次 fork 让进程**不再是会话 leader**(只有 leader 能重新获取控制终端),彻底断绝与终端的联系。
+
+## 变体验证(3 题,全过=学会)
+
+1. 父进程 `fork()` 后子进程调 `_exit(0)` 退出,父进程一直没调 `waitpid()` → **僵尸进程**(子死、父活、未回收)
+2. 陷阱题:父进程 alive,子进程用 `daemon()/setsid()` 脱离终端后台运行 → **守护进程**(关键看 setsid,跟父死不死无关)
+3. 陷阱题:终端按 `Ctrl+Z` 挂起程序再 `bg` 后台 → **不是守护进程**(还在终端会话里,能收到 SIGHUP,终端关了进程也会被杀)
+
+## 口述要点(面试怎么讲)
+
+- **结论先行**:僵尸=子死未收尸,孤儿=父死被 init 收养,守护=脱离终端后台跑
+- **僵尸为什么存在**:子进程退出后内核保留其 PCB 信息供父进程查询(exit code/资源使用情况),父进程不调 wait 回收则 PCB 一直占着。解法:wait 回收 / 双 fork / signal(SIGCHLD, SIG_IGN)
+- **孤儿怎么处理**:被 init(PID 1)收养,init 等其执行完后调 wait 回收,不会变僵尸。注意用词:孤儿是"被收养**继续运行**",不是被"回收清除"(那是僵尸的处理)
+- **为什么需要 setsid**:创建新会话,成为 session leader,脱离原来的控制终端;终端关了不影响守护进程(不收 SIGHUP)。直接 fork 的子进程仍连着终端,会随终端关闭被杀
+- **易错点**:以为守护进程必须父进程先死(其实关键看 setsid);ctrl+Z+bg 当成守护(其实只是作业管理,没脱离终端)
+
+## 关系网络
+
+| 相邻概念 | 关系 | 孤立理解会犯的错 |
+|---|---|---|
+| 进程 vs 线程 | 僵尸/孤儿是进程特有,线程共享地址空间不存在"收养" | 把僵尸概念套到线程上 |
+| exit() vs pthread_exit | exit 产生僵尸可能,pthread_exit 不变僵尸 | 混淆两者效果 |
+| 信号 SIGCHLD | 父进程收到 SIGCHLD 应调 wait 回收,可设 SIG_IGN 跳过 | 不处理 SIGCHLD 堆积僵尸 |
+| IPC 通信 | 守护进程常作为服务端接收 IPC 连接 | 把守护进程当普通子进程 |
+| RTOS 任务 | RTOS 无进程/僵尸概念(任务退出 OS 自动回收) | 把 Linux 进程概念搬进 RTOS |
+
+## 学习日期
+
+2026-08-26
+
+---
+
+_每主题一页,复习时只翻本目录。_

+ 95 - 0
X-Knowledge-Base/raw/面试八股/43.TCP如何保证可靠传输.md

@@ -0,0 +1,95 @@
+## TCP 如何保证可靠传输
+
+## 判别规则(核心,唯一要记的)
+
+1. **看"有没有确认机制"**:发了数据对方要回 ACK,收到 ACK 才算成功;没收到 ACK 就重传 → **TCP 可靠**
+2. **看"能不能控制速度"**:发送方根据接收方窗口(流量控制)和网络状况(拥塞控制)调整发送速度 → **TCP 不会淹没对方/网络**
+3. **看"丢包了怎么办"**:超时重传——发了没 ACK 就重发;快速重传——收到 3 个重复 ACK 立即重传(不用等超时) → **TCP 丢包有兜底**
+
+一句话:**"TCP 靠 ACK 确认知道对方收没收到,靠重传保证丢了就重发,靠滑动窗口控制速度不淹没对方,靠拥塞控制不搞崩网络。"**
+
+## 抽象描述(一句话本质)
+
+TCP 通过**序号 + 确认 + 重传 + 校验 + 流量控制 + 拥塞控制**六大机制保证可靠传输,核心是让发送方知道「发了什么、丢了没有、对方收到没有、要不要减速」。
+
+## 六大机制速查
+
+| 机制 | 作用 | 解决的问题 |
+|---|---|---|
+| 序号(Sequence Number) | 标记每个字节的位置 | 数据丢失/乱序/重复 |
+| 确认号(ACK) | 告诉对方"收到哪了" | 丢包检测 |
+| 超时重传 | 定时器超时未收到 ACK 就重发 | 丢包 |
+| 快速重传 | 收到 3 个重复 ACK 立即重传(不用等超时) | 丢包快速恢复 |
+| 校验和(Checksum) | 检查数据完整性(传输中是否出错) | 数据损坏 |
+| 流量控制(滑动窗口) | 接收方告诉发送方"我能接多少" | 接收方处理不过来 |
+| 拥塞控制 | 发送方根据网络状况调整速度 | 网络过载 |
+
+## 易混对比
+
+| | TCP | UDP |
+|---|---|---|
+| 可靠性 | **可靠**(有序号/确认/重传) | **不可靠**(发了就不管) |
+| 连接 | 面向连接(三次握手) | 无连接 |
+| 速度 | 较慢(要确认) | 快(不确认) |
+| 场景 | 文件传输、网页、邮件 | 视频直播、DNS、游戏 |
+
+| 滑动窗口 | 拥塞控制 |
+|---|---|
+| 接收方能力 | 网络能力 |
+| 告诉发送方"我能接多少" | 发送方根据网络状况调整 |
+| 防止淹没接收方 | 防止搞崩网络 |
+| 两个窗口取最小值决定发送速度 |
+
+| 序号(Seq) | 校验和(Checksum) |
+|---|---|
+| 判断**重复/乱序**(这个包见过没) | 检查**数据完整性**(传输中坏了没) |
+| 接收方据此丢弃重复包、重排乱序包 | 接收方据此丢弃损坏包 |
+| 核心机制 | 辅助校验 |
+
+**累积确认(Cumulative ACK)**:ACK 号表示"该号之前的所有字节都收到了",不用逐包确认。丢一个包只重传该包之后未确认的部分,不是全重传。
+
+## TCP 三次握手 vs 四次挥手
+
+| | 三次握手 | 四次挥手 |
+|---|---|---|
+| 目的 | 建立连接 | 断开连接 |
+| 次数 | 3 次 | 4 次 |
+| 为什么 | SYN+ACK 合并(两次) | FIN 和 ACK 分开(半关闭) |
+| 确认内容 | 确认双方收发能力 | 确认双方都知道连接关闭 |
+
+**两次握手的问题**:旧的 SYN 延迟到达 → 服务器以为是新连接 → 分配资源等待 → 客户端没发起 → 浪费资源。三次握手让服务器确认客户端能收能发。
+
+**为什么挥手四次**:TCP 是全双工,一方发 FIN 只表示"我不发了",但还能接收。对方可能还有数据要发,所以 ACK 和 FIN 分开发送(半关闭状态)。
+
+## 变体验证(3 题,全过=学会)
+
+1. TCP 发送方发了一个包,10秒后没收到 ACK,重传了。接收方其实收到了,只是 ACK 回得慢。接收方收到重复包时,**检查序号**发现已经接收过,丢弃重复数据,重发 ACK。发送方收到重复 ACK 停止重传。 → **序号机制判断重复**
+2. 陷阱题:"TCP 有拥塞控制,所以 TCP 传输一定是可靠的" → **错**,拥塞控制只管速度,网络崩溃/物理链路断了/对方进程崩溃 → TCP 也无法保证
+3. 陷阱题:"UDP 没有序号、没有确认,所以 UDP 一定丢包" → **错**,UDP"不可靠"是指没有确认和重传机制,不是一定丢包。网络良好时 UDP 数据包很可能正常到达
+
+## 口述要点(面试怎么讲)
+
+- **结论先行**:TCP 靠六大机制保证可靠:序号、确认、重传、校验、流量控制、拥塞控制
+- **可靠不是绝对可靠**:网络崩溃、物理链路断了、对方崩溃 → TCP 也无法保证
+- **三次握手为什么两次不行**:防止旧 SYN 延迟到达造成资源浪费;两次握手服务器无法确认客户端能收
+- **为什么视频直播用 UDP**:可以容忍少量丢包,不能容忍延迟;UDP 没有确认/重传/拥塞控制,开销小速度快
+- **滑动窗口 vs 拥塞控制**:滑动窗口 = 接收方能力;拥塞控制 = 网络能力。两个窗口取最小值决定发送速度
+- **易错点**:以为 TCP 绝对可靠;以为 UDP 一定丢包;混淆序号(判断重复)和校验和(检查完整性)
+
+## 关系网络
+
+| 相邻概念 | 关系 | 孤立理解会犯的错 |
+|---|---|---|
+| UDP | TCP 的对照组,UDP 没有序号/确认/重传,所以不可靠但快 | 以为 UDP 一定丢包 |
+| 进程 vs 线程 | TCP 连接是进程级别的,线程共享地址空间不涉及 TCP | 把 TCP 连接当线程间通信 |
+| 僵尸/孤儿进程 | TCP 连接的进程退出后,连接会关闭;父进程不回收连接资源可能泄漏 | 混淆进程回收和连接回收 |
+| 滑动窗口 vs 拥塞控制 | 滑动窗口 = 接收方能力;拥塞控制 = 网络能力。两个窗口取最小值 | 只记一个忘了另一个 |
+| 三次握手 vs 四次挥手 | 握手两次合并(SYN+ACK),挥手两次分开(FIN 和 ACK 分开)因为半关闭 | 混淆握手和挥手的次数差异 |
+
+## 学习日期
+
+2026-08-26
+
+---
+
+_每主题一页,复习时只翻本目录。_

+ 77 - 0
X-Knowledge-Base/raw/面试八股/44.C++-struct-vs-class.md

@@ -0,0 +1,77 @@
+## C++ struct vs class
+
+## 判别规则(核心,唯一要记的)
+
+1. **看"默认访问权限"**:成员默认 public → struct;成员默认 private → class
+2. **看"默认继承方式"**:继承默认 public → struct;继承默认 private → class
+
+一句话:**"C++ 里 struct 和 class 功能完全相同,唯一区别是默认访问权限和默认继承方式:struct 默认 public,class 默认 private。"**
+
+## 抽象描述(一句话本质)
+
+struct 和 class 在 C++ 中功能几乎完全相同(内存布局、类型系统、构造/析构、继承都一致),核心区别是**默认访问权限**(struct=public,class=private)和**默认继承方式**(struct=public 继承,class=private 继承)。
+
+## 易混对比
+
+| | struct | class |
+|---|---|---|
+| 默认访问权限 | **public** | **private** |
+| 默认继承方式 | **public 继承** | **private 继承** |
+| 模板参数(C++11前) | 不能用(必须用 class/typename) | 能用 |
+| 内存布局 | 相同 | 相同 |
+| 类型系统 | 相同 | 相同 |
+| 能否有方法/构造/析构 | ✅ 能 | ✅ 能 |
+| 典型用途 | POD 数据、聚合体 | 封装、继承、多态 |
+
+| C 语言 struct | C++ struct |
+|---|---|
+| 只能放数据成员 | 可以有方法、构造、析构、继承 |
+| 没有访问控制 | 有访问控制(默认 public) |
+| 不能用 template | 可以用 template |
+
+**两者 sizeof 无区别**:同样的成员,struct 和 class 的内存布局、对齐、大小完全一致(成员对齐规则相同,见主题14)。区别只在默认访问权限这一层,不体现在内存里。
+
+## 为什么 C++ 保留 struct
+
+- **兼容 C 代码**:C 程序能无缝迁移到 C++
+- class 是新增关键字:强调**封装/不透明类型**的面向对象语义
+- 用途区别是**习惯和公司规范**,不是功能限制
+
+## struct/class vs union(本质区别)
+
+| | struct/class | union |
+|---|---|---|
+| 内存 | 成员内存**累加** | 成员**共用一块**内存,大小=最大成员 |
+| 访问 | 所有成员同时有效 | 同一时刻只有一个成员有效 |
+| 用途 | 组合数据 | 协议多解析方式、节省内存、类型转换 |
+
+## 变体验证(3 题,全过=学会)
+
+1. `struct Point { int x, y; };` 外面写 `Point p; p.x = 10;` → **能编译**(struct 默认 public)
+2. 陷阱题:`class A { int x; };` 外面写 `A a; a.x = 5;` 报错,改成 `struct A` 就能编译 → **对**(class 默认 private,struct 默认 public)
+3. 陷阱题:"struct 是给数据用的,class 是给带方法的类用的,不能混用" → **错**,两者功能完全相同,区分是习惯/规范
+
+## 口述要点(面试怎么讲)
+
+- **结论先行**:功能完全相同,唯一区别是默认访问权限(public vs private)+ 默认继承方式(public vs private 继承)
+- **为什么保留 struct**:兼容 C 代码,C 程序无缝迁移;class 强调封装语义
+- **有没有构造析构**:两者都有;sizeof 无区别(内存布局相同)
+- **union 区别**:struct/class 内存累加,union 共用一块取最大,同一时刻只有一个成员有效(嵌入式常用于协议解析)
+- **易错点**:以为 struct 不能有方法/继承;以为 struct 是 C 语言定义无构造析构;把 union 当 struct 用
+
+## 关系网络
+
+| 相邻概念 | 关系 | 孤立理解会犯的错 |
+|---|---|---|
+| struct vs union(主题15) | struct/class 内存叠加,union 共用一块内存取最大 | 以为 union 能同时存多个成员 |
+| 结构体对齐(主题14) | struct/class 成员对齐规则相同 | 以为 class 有特殊对齐 |
+| C 语言 struct | C++ struct = C struct + 面向对象能力(方法/访问控制/继承) | 把 C++ struct 当 C struct 用 |
+| 封装/继承 | class 强调封装,struct 强调聚合数据 | 以为 struct 不能继承 |
+
+## 学习日期
+
+2026-08-26
+
+---
+
+_每主题一页,复习时只翻本目录。_

+ 161 - 0
X-Knowledge-Base/raw/面试八股/45.C++-构造析构.md

@@ -0,0 +1,161 @@
+## C++ 构造/析构(含 RAII)
+
+## 判别规则(核心,唯一要记的)
+
+1. **看"谁在管资源"**:对象放栈上靠自动析构 → **RAII 安全**;`new`/`delete` 手动管理 → **中途 return/异常会泄漏**
+2. **看"对象是不是临时"**:临时对象(用完即弃)→ **移动**;还要继续用的已存在对象 → **拷贝**。移动 = 偷指针 + 原对象置空,O(1);拷贝 = 复制数据,深拷贝独立
+3. **看"有没有显式禁用"**:只要没显式删除(`=delete`),编译器默认生成拷贝构造(声明了析构则移动构造不生成)→ **能编译**;显式 `=delete` 才不能
+4. **看"容器重定位元素"(移动优先原则)**:标准库(vector/string)需要移动元素时**默认走移动**,只有移动不可用时(被 `=delete` / 未定义 / 非 `noexcept`)才退回拷贝 → 这就是"只能移动不能拷贝"的对象(unique_ptr)也能存 vector 的原因
+
+一句话:**"构造=创建时自动初始化,析构=销毁时自动清理;RAII 是栈对象自动析构,不是 new/delete;移动给临时对象、拷贝给存活对象;有指针成员必须深拷贝;容器默认走移动,移动不可用才走拷贝。"**
+
+## 抽象描述(一句话本质)
+
+构造函数 = 对象创建时自动执行、负责**初始化/获取资源**;析构函数 = 对象销毁时自动执行、负责**清理/释放资源**。构造可重载多个(默认/带参/拷贝/移动),析构只能一个。
+
+## 构造/析构 vs 拷贝/移动
+
+| | 构造函数 | 析构函数 |
+|---|---|---|
+| 调用时机 | 对象创建时 | 对象销毁时 |
+| 个数 | 可重载多个 | 只能一个 |
+| 命名 | 与类名相同 | 类名前加 `~` |
+| 能否重载 | ✅ | ❌ |
+| 用途 | 初始化成员、获取资源 | 清理资源、释放内存 |
+
+| 默认构造 | 拷贝构造 | 移动构造 |
+|---|---|---|
+| `ClassName()` | `ClassName(const ClassName&)` | `ClassName(ClassName&&)` |
+| 无参,编译器默认生成 | 用已存在对象建新对象(深拷贝) | 移动临时对象资源(性能优化) |
+| 数据初始化 | 数据复制 | 资源转移,原对象置空 |
+
+## RAII(资源获取即初始化)
+
+- **核心**:资源在构造函数获取,在析构函数释放
+- **保证**:无论正常 return 还是异常(栈展开 stack unwinding),栈对象析构都会执行 → 不会泄漏
+- **正确写法**:对象放栈上(`FileGuard guard(fp);`),不用 new/delete
+- **错误写法**:`new`/`delete` 手动管理,中间 return → delete 不执行 → 泄漏
+
+```cpp
+class FileGuard {
+public:
+    FileGuard(FILE* f) : fp(f) {}
+    ~FileGuard() { fclose(fp); }
+private:
+    FILE* fp;
+};
+void func() {
+    FILE* fp = fopen("a.txt", "w");
+    FileGuard guard(fp);   // 栈对象,作用域结束自动 fclose
+}
+```
+
+## 深拷贝 vs 浅拷贝 vs 移动
+
+| | 浅拷贝 | 深拷贝 | 移动 |
+|---|---|---|---|
+| 指针成员 | 复制指针值(共享内存) | 新分配内存并复制数据 | 偷走指针,原对象置空 |
+| 两个对象 | 指向同一块内存 | 完全独立 | 一个持有资源,一个空 |
+| 后果 | 双重释放崩溃 | 安全 | 安全且 O(1) |
+| 何时用 | 禁用 | 存活的已存在对象 | 临时对象 |
+
+## 移动构造三要素
+
+1. **参数是右值引用** `ClassName(ClassName&&)`
+2. **转移资源**:直接搬走原对象的指针/句柄,不复制数据
+3. **原对象置空**:`other.m_data = nullptr;`——防止原对象析构时 `delete` 同一块内存 → 双重释放崩溃
+
+**移动口诀**:**拷贝 = 复制一份,移动 = 把东西搬走并给原对象留个空盒子。**
+
+## 移动构造可编译示例
+
+```cpp
+class Buffer {
+public:
+    Buffer(size_t size) : m_size(size) {
+        m_data = new char[m_size];
+    }
+    // 拷贝构造:深拷贝
+    Buffer(const Buffer& other) : m_size(other.m_size) {
+        m_data = new char[m_size];
+        memcpy(m_data, other.m_data, m_size);
+    }
+    // 移动构造:资源转移,原对象置空防双重释放
+    Buffer(Buffer&& other) noexcept : m_data(other.m_data), m_size(other.m_size) {
+        other.m_data = nullptr;
+        other.m_size = 0;
+    }
+    ~Buffer() { delete[] m_data; }   // nullptr 时 delete 安全
+private:
+    char* m_data;
+    size_t m_size;
+};
+```
+
+## 移动优先原则(标准库行为,核心考点)
+
+标准库容器(vector/string 等)在**重定位元素**(扩容搬移)时:
+
+1. **默认走移动**:优先调用移动构造,性能高(O(1) 搬指针)
+2. **移动不可用才走拷贝**:当移动构造被 `=delete`、未定义、或**非 `noexcept`** 时,退回拷贝构造(O(n) 复制)
+3. **为什么 `noexcept` 很关键**:vector 扩容必须保证**强异常安全**(失败则回滚原状)。如果移动可能抛异常,vector 无法回滚(元素已被搬走),所以会退回用拷贝;移动构造声明 `noexcept` 后,vector 才放心用移动
+4. **推论**:`std::unique_ptr`(只移动、不能拷贝)能安全存进 vector——扩容时用移动构造,原指针置空
+
+## C++17 保证复制省略(Guaranteed Copy Elision)
+
+- **规则**:`return T();`、`T t = T();` 等场景,C++17 保证**直接在目标位置构造**,不调用任何拷贝/移动构造
+- **推论**:即使拷贝构造被 `=delete`、移动构造也不存在,这种代码在 C++17 下**依然能编译**
+- **注意**:C++11/14 下 `return T()` 仍需要移动或拷贝构造(会走移动,移动不可用才拷贝)——嵌入式面试按 C++11 讲,C++17 是加分项
+
+## 易混对比
+
+| | 自动管理(RAII) | 手动管理(new/delete) |
+|---|---|---|
+| 资源释放 | 析构自动执行,绝不遗漏 | 必须手动 delete,return/异常就漏 |
+| 安全 | ✅ | ⚠️ 易泄漏 |
+| 典型 | 栈对象、unique_ptr、vector | 裸指针、new[] |
+
+| 拷贝 | 移动 |
+|---|---|
+| 给"还要继续用的已存在对象" | 给"用完即弃的临时对象" |
+| 深拷贝,数据独立 | 偷资源,原对象置空 |
+| O(n) 复制数据 | O(1) 搬指针 |
+| 移动不可用时的兜底 | **容器默认优先使用** |
+
+| C++11 | C++17 |
+|---|---|
+| `return T()` 需要移动或拷贝构造 | 保证复制省略,无需任何构造 |
+| 移动可用走移动,不可用走拷贝 | 直接构造,零拷贝 |
+
+## 变体验证(3 题,全过=学会)
+
+1. `class FileGuard { ... ~FileGuard() { fclose(fp); } };` 栈对象在 func 中间 return → **文件会正常关闭**(栈对象自动析构,无论什么路径退出)
+2. `std::string s2 = s1;` → **拷贝**(s1 是左值要复用);`std::string s3 = std::string("world");` → **移动**(临时右值用完即弃)
+3. 陷阱题:`class Y { Y(const Y&) = delete; };`(声明了析构)→ `Y a = makeY();` 在 C++11/14 下 **编译失败**(拷贝被 delete,移动因声明析构不生成);**C++17 下能编译**(保证复制省略,直接构造不调用拷贝/移动)
+
+## 口述要点(面试怎么讲)
+
+- **结论先行**:构造=创建时初始化,析构=销毁时清理;RAII = 资源构造获取/析构释放,靠栈对象自动析构保证不泄漏
+- **为什么 RAII 防泄漏**:正常 return 和异常栈展开(stack unwinding)都会依次调用栈对象析构 → 无路径遗漏
+- **深拷贝 vs 移动**:深拷贝给存活对象(数据独立);移动给临时对象(偷指针+置空,O(1))。浅拷贝双重释放崩溃
+- **vector 扩容走什么**:**默认走移动,移动不可用才走拷贝**;移动必须 `noexcept`,vector 才敢用它(保证强异常安全);unique_ptr 只移动不拷贝也能存 vector
+- **C++17 保证复制省略**:`return T()` 直接构造,拷贝被 `=delete` 也能编译(加分项)
+- **易错点**:把 new/delete 当 RAII;以为移动后资源不独立;以为声明析构后拷贝构造仍生成移动构造;以为"没有拷贝就不能存 vector"
+
+## 关系网络
+
+| 相邻概念 | 关系 | 孤立理解会犯的错 |
+|---|---|---|
+| RAII vs 资源管理 | RAII 是 C++ 防泄漏的根基,比手动 new/delete 安全 | 以为 new/delete 就是 RAII |
+| struct vs class(主题44) | 两者都有构造/析构,用法相同 | 以为 struct 没有构造析构 |
+| 堆 vs 栈(主题11) | 栈对象自动析构(RAII),堆对象需手动 delete | 以为 new 出来的对象也会自动清理 |
+| 内存泄漏(主题12) | 手动 new 无对应 delete = 泄漏;RAII 根治 | 靠手动记得 delete,不靠机制 |
+| 原子/锁(主题21/27) | RAII 常用于锁管理(构造加锁、析构解锁) | 手动 lock/unlock,中途 return 死锁 |
+
+## 学习日期
+
+2026-08-26
+
+---
+
+_每主题一页,复习时只翻本目录。_

+ 91 - 0
X-Knowledge-Base/raw/面试八股/46.SMP-多核.md

@@ -0,0 +1,91 @@
+## SMP/多核
+
+## 判别规则(核心,唯一要记的)
+
+1. **看"是否真同时"**:多核多线程同一时刻各占一个核 → **并行**;单核时间片轮流 → **并发**(不是并行)
+2. **看"是否共享数据"**:核间共享数据 → **必须原子操作/锁**(否则丢失更新/数据竞争);各核私有数据 → 不需要锁
+3. **看"缓存是否打架"**:共享数据跨核 → 靠**缓存一致性协议(MESI)**保证;互不相干的变量挤在同一缓存行 → **伪共享**(性能骤降),用对齐/填充解决
+
+一句话:**"SMP = 多核对等共享内存;共享数据必须同步;缓存一致性和伪共享是多核的坑;关中断只关当前核,多核要自旋锁。"**
+
+## 抽象描述(一句话本质)
+
+SMP(对称多处理)= 多个处理器核心**共享同一块物理内存、同一个操作系统、完全对等**。每个核有自己的寄存器和缓存(L1/L2),问题出在"共享数据 + 各自缓存"的冲突上。
+
+## 易混对比
+
+| | 并行 | 并发 |
+|---|---|---|
+| 定义 | 同一时刻**同时**执行多个 | 同一时刻只执行一个,轮流切换 |
+| 需要 | 多核/多CPU | 单核即可 |
+| 例子 | 4 核跑 4 线程 | 单核跑多线程 |
+| 数据竞争 | 多核共享数据必出 | 单核也要注意(中断/调度) |
+
+| | SMP | AMP(非对称多处理) |
+|---|---|---|
+| 核的关系 | 对等(对称) | 不等(异构分工) |
+| 内存 | 共享同一块 | 可独立/私有 |
+| OS | 一个 OS 管理所有核 | 可多个/专用核 |
+| 例子 | 普通多核 PC/服务器 CPU | 大小核 big.LITTLE、GPU+CPU |
+
+## 多核的坑:缓存一致性 / 伪共享 / 数据竞争
+
+| 缓存一致性 | 原子性 | 伪共享 |
+|---|---|---|
+| 核间缓存与内存不一致 | 操作不可分割 | 不同变量同缓存行互相干扰 |
+| 靠缓存一致性协议(MESI) | 靠原子指令/锁 | 靠缓存行对齐/填充 |
+
+**MESI 协议**(四状态):Modified 已改 / Exclusive 独占 / Shared 共享 / Invalid 失效。核改数据 → 标记 Modified,广播让其他核缓存失效(Invalid)→ 其他核再读时从内存/该核同步最新值。
+
+**伪共享判断**:变量地址间隔 < 缓存行大小(通常 64 字节)→ 可能伪共享。如 `int arr[8]`(32 字节 < 64)中 `arr[0]` 和 `arr[1]` 同缓存行;`arr[0]` 和 `arr[100]`(400 字节 > 64)绝不会。
+
+**数据竞争**:多核 `count++` 是"读→改→写"三步,同时执行被切开 → 丢失更新(A 读 0、B 读 0,都写 1,结果 1 不是 2)。
+
+## 原子操作 vs 锁 vs 自旋锁
+
+| | 原子操作 | 锁(互斥锁) | 自旋锁 |
+|---|---|---|---|
+| 实现 | 硬件原子指令(CAS/test-and-set) | 基于原子指令 + 阻塞/睡眠 | 忙等轮询 |
+| 开销 | 最小 | 有上下文切换 | 忙等耗 CPU |
+| 适用 | 单变量简单操作(count++) | 多步骤临界区 | 多核短临界区 |
+| 是否阻塞 | 否 | 是(睡眠) | 忙等 |
+
+**锁本身就是用原子指令实现的**。原子操作不阻塞别人,锁会阻塞等待。
+
+## 多核临界区:关中断不够
+
+- **单核**(FreeRTOS):关中断(taskENTER_CRITICAL)可保护临界区(主题27)
+- **多核**:关中断**只关当前核**,其他核照样能改共享数据 → 必须用**自旋锁**或**原子操作**
+- 自旋锁也有优先级反转问题
+
+## 变体验证(3 题,全过=学会)
+
+1. 4 核 CPU 跑 2 个线程都在核 0 → **并发**;绑到核 0/核 1 → **并行**
+2. 陷阱题:两个核上 `count++`(共享变量)不加锁,说"不同核不会同时写,安全" → **错**,`count++` 读改写被切开,丢失更新(结果 1 不是 2)
+3. 陷阱题:`arr[0]` 和 `arr[100]` 说"离得远没伪共享" → **对**(400 字节 > 64 缓存行,不可能同缓存行);但 `arr[0]` 和 `arr[1]`(4 字节 < 64)→ **会伪共享**
+
+## 口述要点(面试怎么讲)
+
+- **结论先行**:SMP = 多核对等共享内存/OS;多核真并行、共享数据必须同步;关中断只关当前核
+- **缓存一致性**:核各有缓存,改了数据要广播让其他核失效(MESI),否则读到旧值
+- **伪共享**:不相干变量挤同一缓存行,互相写导致反复失效,性能骤降;靠对齐/填充拉开距离
+- **原子 vs 锁**:原子操作单变量一步完成不阻塞;锁多步骤临界区会阻塞;自旋锁多核忙等
+- **多核临界区**:关中断只关当前核,其他核照样改数据 → 自旋锁/原子操作
+- **易错点**:把并发当并行;以为多核不用加锁;以为关中断多核有效;伪共享判断只看"逻辑无关"不看地址间隔
+
+## 关系网络
+
+| 相邻概念 | 关系 | 孤立理解会犯的错 |
+|---|---|---|
+| 临界区(主题27) | 单核关中断即可;多核必须自旋锁/原子 | 以为关中断多核也有效 |
+| 原子操作(主题21) | 多核共享单变量的保护手段 | 以为原子操作要阻塞别人 |
+| 进程 vs 线程 | 多核多线程真并行,共享数据竞争更易触发 | 以为多核不用加锁 |
+| 优先级反转(主题26) | 多核自旋锁也有优先级反转问题 | 以为自旋锁没开销 |
+
+## 学习日期
+
+2026-08-26
+
+---
+
+_每主题一页,复习时只翻本目录。_

+ 55 - 0
X-Knowledge-Base/raw/面试八股/第四批复习总结-答案.md

@@ -0,0 +1,55 @@
+# 第四批复习总结 · 答案解析
+
+> ⚠️ 做完 `第四批复习总结.md` 的全部 36 题后再翻开本文件对照。
+> 每道题给答案 + 一句话解析,解析都指向对应主题页。
+
+---
+
+## 判断题(对/错 + 一句话理由)
+
+1. **错**。每个标签页是独立**进程**(独立地址空间隔离),不是线程;线程共享地址空间会一个崩全崩。→ `41.进程-vs-线程`
+2. **错**。孤儿是"被 init **收养继续运行**",不是被"回收清除";"回收"是僵尸的处理(父进程 wait 清 PCB)。→ `42.僵尸-孤儿-守护进程`
+3. **错**。判断守护进程的关键是**是否 setsid 脱离终端**,跟父进程死不死无关;父进程活着也可以是守护进程。→ `42.僵尸-孤儿-守护进程`
+4. **错**。Ctrl+Z+bg 只是作业管理(后台任务),进程还连着终端会话,会收到 SIGHUP;守护进程必须脱离控制终端。→ `42.僵尸-孤儿-守护进程`
+5. **错**。拥塞控制只管速度,TCP 可靠是"尽力而为";网络崩溃/物理链路断/对方进程崩溃时 TCP 也无法保证。→ `43.TCP如何保证可靠传输`
+6. **错**。"不可靠"指没有确认/重传机制,**不是一定丢包**;网络良好时 UDP 包很可能正常到达。→ `43.TCP如何保证可靠传输`
+7. **错**。判重复靠**序号(Seq)**;校验和(Checksum)只查数据完整性(传输中坏了没)。→ `43.TCP如何保证可靠传输`
+8. **错**。C++ 中 struct 和 class **功能完全相同**,都能放数据+方法;区别只是默认访问权限和默认继承方式。→ `44.C++-struct-vs-class`
+9. **对**。struct 默认 public(`a.x` 可访问),class 默认 private(`a.x` 报错);只是关键字一换,权限就变。→ `44.C++-struct-vs-class`
+10. **错**。同样的成员,struct 和 class 内存布局、对齐、大小完全一致,**sizeof 无区别**。→ `44.C++-struct-vs-class`
+11. **对**。RAII = 栈对象自动析构,无论正常 return 还是异常栈展开(stack unwinding)析构都执行。→ `45.C++-构造析构`
+12. **错**。移动是**偷指针 + 原对象置空**,O(1) 搬资源不复制数据;拷贝才复制整份数据(O(n))。→ `45.C++-构造析构`
+13. **错**。声明了析构函数会**抑制移动构造的隐式生成**(拷贝构造仍会生成)。→ `45.C++-构造析构`
+14. **错**。多核关中断**只关当前核**,其他核照样能改共享数据;多核要用自旋锁或原子操作。→ `46.SMP-多核`
+15. **错**(正好相反)。`arr[0]` 和 `arr[100]` 间隔 400 字节 > 64 缓存行,**绝不会**伪共享;反而 `arr[0]`/`arr[1]`(4 字节 < 64)会。→ `46.SMP-多核`
+16. **错**。单核同一时刻只能执行一个线程(并发/时间片轮转);**并行**需要多核。→ `46.SMP-多核`
+
+## 填空题
+
+17. **wait()/waitpid()**——父进程不回收,子进程残留 PCB 成僵尸。→ `42.僵尸-孤儿-守护进程`
+18. **init**(PID 1)——孤儿院,收养并等运行完再回收,不会变僵尸。→ `42.僵尸-孤儿-守护进程`
+19. **setsid()**——创建新会话、成为 session leader、脱离控制终端。→ `42.僵尸-孤儿-守护进程`
+20. **序号(Seq)/ 校验和(Checksum)**——序号判重复乱序,校验和查损坏。→ `43.TCP如何保证可靠传输`
+21. **滑动窗口 / 拥塞控制 / 最小**——接收方能力 + 网络能力,两个窗口取最小值。→ `43.TCP如何保证可靠传输`
+22. **ACK**——全双工半关闭:一方 FIN 只表示不再发,还能收,所以 ACK 和 FIN 分开。→ `43.TCP如何保证可靠传输`
+23. **public / private**——struct 默认公开,class 默认私有。→ `44.C++-struct-vs-class`
+24. **public / private**——继承方式也有默认差异。→ `44.C++-struct-vs-class`
+25. **ClassName&&**——右值引用参数。→ `45.C++-构造析构`
+26. **转移资源 / 原对象置空**——转移后把原指针置 nullptr,防析构双重释放。→ `45.C++-构造析构`
+27. **移动 / 拷贝**——移动优先原则:默认走移动,移动不可用(=delete/未定义/非 noexcept)才拷贝。→ `45.C++-构造析构`
+28. **noexcept**——移动可能抛异常时 vector 无法保证强异常安全,会回退用拷贝。→ `45.C++-构造析构`
+29. **保证复制省略(Guaranteed Copy Elision)**——`return T();` 直接构造,C++11/14 不行。→ `45.C++-构造析构`
+30. **自旋锁**——多核临界区要忙等锁;关中断只关本核无效。→ `46.SMP-多核`
+31. **小于**——地址间隔 < 缓存行大小(64 字节)才可能伪共享。→ `46.SMP-多核`
+
+## 场景 / 代码判断
+
+32. **线程**。要共享数据 + 轻快切换 → 线程(共享地址空间、切换只换寄存器/栈指针)。线程崩 = 进程崩:线程共享进程的地址空间和资源,一个线程写坏共享部分,整个进程资源跟着坏;进程有独立地址空间(隔离墙)。→ `41.进程-vs-线程`
+33. **方案一**:`signal(SIGCHLD, SIG_IGN)` 忽略退出信号,内核自动回收;**方案二**:**双 fork**——子进程再 fork 孙进程后自己立刻退出,孙进程变孤儿被 init 收养自动回收,父进程完全不用管。→ `42.僵尸-孤儿-守护进程`
+34. **UDP**。视频直播可容忍**少量丢包**(丢几帧没关系),但不能容忍**延迟**;TCP 要确认/重传/握手,慢且可能卡顿。→ `43.TCP如何保证可靠传输`
+35. **能**。`unique_ptr` 只移动不拷贝,vector 扩容时调用它的**移动构造**(偷走资源、原指针置空),安全;因为容器默认走移动。→ `45.C++-构造析构`
+36. **不一定对**。`count++` 是"读→改→写"三步,多核同时执行被切开:A 读 0、B 也读 0,都写 1,结果 1 不是 2(**丢失更新/数据竞争**)。必须用原子操作或锁。→ `46.SMP-多核`
+
+---
+
+_错题 > 3 道:回到对应主题页重学第 5 步变体验证。_

+ 180 - 0
X-Knowledge-Base/raw/面试八股/第四批复习总结.md

@@ -0,0 +1,180 @@
+# 第四批 OS / 网络 / C++ 八股 · 复习总结(6 主题)
+
+> 使用说明:先自测「判别规则速查表」,遮住右列自答;再做「综合练习题」,最后对答案。
+> 面试前只翻本目录,不背题。
+
+---
+
+## 一、判别规则速查表(遮右自测)
+
+| #  | 主题                 | 一句话判别规则                                                                                                                                  |
+| -- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
+| 41 | 进程 vs 线程         | 要**崩溃隔离/资源独立 → 进程**(切换重:换地址空间);要**轻快/共享数据 → 线程**(切换轻、一个崩全崩);线程共享变量必须同步                                        |
+| 42 | 僵尸/孤儿/守护进程   | 子死+父未 wait=**僵尸**;父先死+子活=**孤儿**(init 收养);主动 **setsid 脱离终端=守护**;ctrl+Z+bg 不算(还连终端会收 SIGHUP)                           |
+| 43 | TCP 如何保证可靠     | **ACK 确认 + 重传(超时/快重传)+ 序号(判重复/乱序)+ 校验(查损坏)+ 滑动窗口(接收方)+ 拥塞控制(网络)**;可靠是"尽力而为"非绝对                      |
+| 44 | C++ struct vs class  | **功能完全相同**;唯一区别=**默认访问权限**(struct public / class private)+ **默认继承**(struct public 继承 / class private 继承)               |
+| 45 | C++ 构造/析构(RAII)| 构造=创建时初始化、析构=销毁时清理;**RAII=栈对象自动析构**(非 new/delete);移动给临时对象、拷贝给存活对象;**容器默认走移动,移动不可用才拷贝**        |
+| 46 | SMP/多核             | 多核=**真并行**(单核=并发);**共享数据必须原子/锁**;**缓存一致性(MESI)+ 伪共享(同缓存行)**是坑;**关中断只关本核**,多核要自旋锁                     |
+
+---
+
+## 二、易混对比集中营(高频考点串讲)
+
+### 进程 vs 线程
+
+|        | 进程         | 线程                 |
+| ------ | ------------ | -------------------- |
+| 地址空间 | 独立(隔墙) | 共享(同一进程)     |
+| 切换开销 | 重(换页表/TLB) | 轻(换寄存器/栈指针)|
+| 崩溃影响 | 崩一个不影响其他 | 一个崩 → 整个进程崩 |
+| 通信   | IPC(管道/消息/共享内存) | 共享变量 + 锁 |
+
+### 僵尸 / 孤儿 / 守护
+
+|        | 僵尸         | 孤儿               | 守护             |
+| ------ | ------------ | ------------------ | ---------------- |
+| 谁死了 | 子死,父活   | 父死,子活         | 谁都没死         |
+| 本质   | 残留 PCB 未回收 | init 收养继续跑 | 主动脱离终端后台 |
+| 处理   | 父 wait 回收 | init 等完再回收    | 自己独立         |
+
+**僵尸三解法**:父 wait() / 双 fork(孙被 init 收)/ signal(SIGCHLD, SIG_IGN)。
+**守护创建**:fork → setsid → 再 fork(防重新获取终端)→ chdir("/") → umask(0) → close(0/1/2)。
+
+### TCP vs UDP
+
+|        | TCP                          | UDP                     |
+| ------ | ---------------------------- | ----------------------- |
+| 可靠   | 可靠(序号/确认/重传)       | 不可靠(发了不管)      |
+| 连接   | 面向连接(三次握手)         | 无连接                  |
+| 速度   | 慢(要确认)                 | 快(不确认)            |
+| 场景   | 文件/网页/邮件               | 视频直播/DNS/游戏       |
+
+### 滑动窗口 vs 拥塞控制(两个窗口取最小值)
+
+|        | 滑动窗口           | 拥塞控制             |
+| ------ | ------------------ | -------------------- |
+| 能力   | 接收方能力         | 网络能力             |
+| 防     | 淹没接收方         | 搞崩网络             |
+| 手段   | 接收方报 Window    | 慢启动/拥塞避免/快恢复 |
+
+### 序号 vs 校验和
+
+|        | 序号(Seq)      | 校验和(Checksum)       |
+| ------ | ---------------- | ------------------------ |
+| 作用   | 判**重复/乱序** | 查**数据完整性**(坏了没)|
+| 响应   | 丢弃重复/重排    | 丢弃损坏                 |
+
+### 三次握手 vs 四次挥手
+
+|        | 三次握手         | 四次挥手                 |
+| ------ | ---------------- | ------------------------ |
+| 目的   | 建立连接         | 断开连接                 |
+| 次数   | 3(SYN+ACK 合并)| 4(FIN/ACK 分开,半关闭)|
+| 为什么 | 防旧 SYN 浪费资源 | 全双工,一方 FIN 还能收  |
+
+### struct vs class vs union
+
+|            | struct            | class              | union                 |
+| ---------- | ----------------- | ------------------ | --------------------- |
+| 默认访问   | public            | private            | public                |
+| 内存       | 累加              | 累加               | 共用一块(取最大)    |
+| 用途       | 聚合数据          | 封装/多态          | 协议解析/类型转换     |
+| 构造/析构  | 有                | 有                 | 有(C++11 起)        |
+
+### 深拷贝 vs 浅拷贝 vs 移动
+
+|        | 浅拷贝           | 深拷贝             | 移动                 |
+| ------ | ---------------- | ------------------ | -------------------- |
+| 指针   | 复制指针值(共享)| 新分配+复制数据    | 偷指针+原对象置空    |
+| 后果   | 双重释放崩溃     | 安全               | 安全且 O(1)          |
+| 给谁   | 禁用             | 存活的已存在对象   | 用完即弃的临时对象   |
+
+**移动构造三要素**:右值引用参数 + 转移资源 + 原对象置空(防双重释放)。
+
+### 移动优先原则(核心)
+
+- 标准库容器重定位元素:**默认走移动**,移动不可用(`=delete`/未定义/**非 noexcept**)才走拷贝
+- **为什么 noexcept 关键**:vector 扩容要强异常安全,移动可能抛异常就回退拷贝
+- 推论:`std::unique_ptr`(只移动不拷贝)能存 vector
+- C++17 保证复制省略:`return T();` 直接构造,拷贝 `=delete` 也能编译(C++11/14 不行)
+
+### 并行 vs 并发 / SMP vs AMP
+
+|        | 并行               | 并发                 |
+| ------ | ------------------ | -------------------- |
+| 定义   | 同一时刻同时执行   | 轮流切换,同一刻一个 |
+| 需要   | 多核               | 单核即可             |
+
+|        | SMP                | AMP                   |
+| ------ | ------------------ | --------------------- |
+| 核关系 | 对等(对称)       | 不等(异构分工)      |
+| 例子   | 普通多核 CPU       | big.LITTLE、GPU+CPU   |
+
+### 原子操作 vs 锁 vs 自旋锁
+
+|        | 原子操作       | 锁           | 自旋锁         |
+| ------ | -------------- | ------------ | -------------- |
+| 实现   | 硬件原子指令   | 原子指令+睡眠| 忙等轮询       |
+| 开销   | 最小           | 有切换       | 忙等耗 CPU     |
+| 适用   | 单变量(count++)| 多步临界区  | 多核短临界区   |
+
+---
+
+## 三、综合练习题(答完再对答案)
+
+### 判断题(对/错 + 一句话理由)
+
+1. 浏览器一个标签页崩了,其他标签页不受影响,是因为每个标签页用了独立线程。答:
+2. 孤儿进程会被 init 进程"回收清除",就像僵尸被父进程 wait 那样。答:
+3. 一个程序用 daemon() 脱离终端后台运行,但父进程还活着——它不是守护进程,因为守护必须父进程先死。答:
+4. 终端里 Ctrl+Z 挂起再 bg 放到后台的进程,就是守护进程。答:
+5. TCP 有拥塞控制,所以 TCP 传输一定是可靠的。答:
+6. UDP 没有序号和确认,所以 UDP 数据包一定会丢。答:
+7. TCP 接收方靠校验和判断收到的包是不是重复的。答:
+8. C++ 里 struct 只能放数据,class 只能放方法,两者不能混用。答:
+9. `class A { int x; };` 外面写 `A a; a.x = 5;` 报错,改成 `struct A` 就能编译。答:
+10. `struct` 和 `class` 同样的成员,sizeof 结果不同。答:
+11. 把 `new`/`delete` 换成 RAII 后,中途 return 时资源就一定能被释放。答:
+12. 移动构造是复制一份数据给新对象,所以比拷贝构造慢。答:
+13. 一个类声明了析构函数,编译器仍然会隐式生成移动构造函数。答:
+14. 多核系统里,关中断(临界区)可以保护共享数据不被其他核访问。答:
+15. `arr[0]` 和 `arr[100]` 两个变量由不同线程各写一个,因为离得远,绝不会伪共享。答:
+16. 单核 CPU 上跑两个线程,它们同一时刻可以并行执行。答:
+
+### 填空题
+
+17. 僵尸进程产生的原因:子进程已退出、父进程没有调用 ____ 回收。
+18. 孤儿进程最终由 ____(PID 1)收养,等它运行完再回收。
+19. 守护进程创建的关键一步是调用 ____ 创建新会话、脱离控制终端。
+20. TCP 用 ____ 号判断重复/乱序,用 ____ 检查数据完整性。
+21. TCP 靠 ____(接收方能力)和 ____(网络能力)两个窗口控制发送速度,实际取 ____ 值。
+22. TCP 四次挥手比三次握手多一次,是因为 FIN 和 ____ 要分开发送(半关闭状态)。
+23. C++ struct 默认访问权限是 ____,class 默认是 ____。
+24. C++ struct 默认 ____ 继承,class 默认 ____ 继承。
+25. 移动构造的签名是 `ClassName(____)`,参数是右值引用。
+26. 移动构造三要素:右值引用参数、____、____(防双重释放)。
+27. 标准库容器重定位元素时默认走 ____,移动不可用时才走 ____。
+28. 移动构造声明为 ____ 后,vector 扩容才放心用移动(保证强异常安全)。
+29. C++17 的 ____(特性)让 `return T();` 直接构造,无需拷贝/移动构造。
+30. 多核保护临界区要用 ____ 锁(忙等),不能只靠关中断。
+31. 伪共享的判断标准:变量地址间隔 ____(小于/大于)缓存行大小(通常 64 字节)。
+
+### 场景 / 代码判断
+
+32. 场景:多个并发任务都要频繁访问同一份数据,且要求切换轻快 → 用进程还是线程?为什么线程崩会拖垮整个进程?
+33. 场景:父进程不关心子进程退出状态,想彻底不产生僵尸 → 给出两种方案。
+34. 场景:视频直播丢几帧没关系,但不能卡顿 → 用 TCP 还是 UDP?为什么不用另一个?
+35. 代码判断:`std::unique_ptr<int> u(new int(5));` 能不能放进 `std::vector<std::unique_ptr<int>>`?扩容时怎么搬?
+36. 场景:4 核 CPU 上两个线程分别绑核 0、核 1,同时执行 `count++`(共享变量)不加锁 → 结果一定对吗?为什么?
+
+---
+
+## 四、答案(已分离)
+
+答案解析已单独存放,避免自测时不小心看到答案:
+
+> **`第四批复习总结-答案.md`**(同目录)——完成全部 36 题后再翻开对照。
+
+---
+
+_复习目标:每条规则能自己讲出"为什么",不只记住结论。_

+ 5 - 5
X-Knowledge-Base/raw/面试八股/面试八股主题元学习法.md

@@ -183,11 +183,11 @@
 | 勾 | 主题 | 核心判别规则(提示) |
 |:--:|------|---------------------|
 | ✅ | 进程 vs 线程 | 资源隔离 vs 轻量共享;切换开销 |
-|  | 僵尸/孤儿/守护进程 | 父进程未回收=僵尸;父先死=孤儿;脱离终端=守护 |
-|  | TCP 如何保证可靠 | 确认/重传/序号/校验/流量控制/拥塞控制 |
-|  | C++ struct vs class | 默认访问权限 public vs private |
-|  | C++ 构造/析构 | 初始化/清理时机;RAII |
-|  | SMP/多核 | 多核并行;缓存一致性(进阶) |
+|  | 僵尸/孤儿/守护进程 | 父进程未回收=僵尸;父先死=孤儿;脱离终端=守护 |
+|  | TCP 如何保证可靠 | 确认/重传/序号/校验/流量控制/拥塞控制 |
+|  | C++ struct vs class | 默认访问权限 public vs private |
+|  | C++ 构造/析构 | 初始化/清理时机;RAII |
+|  | SMP/多核 | 多核并行;缓存一致性(进阶) |
 
 ---