腾讯 C++ 一面
面试题目
一、自我介绍
- 个人情况介绍
二、基础知识
- 多态的实现机制是什么?
- 如何保证并发安全?
- 了解 CAS 操作吗?
- CAS 有哪些问题?
- ABA 问题了解吗?
- 内核态和用户态的区别是什么?
- 协程有了解过吗?
- HTTP、TCP、UDP 分别是什么,有什么区别?
- TCP 用什么机制保证可靠交付?
- HTTP 可以基于 UDP 实现吗?
- UDP 为什么可以用在游戏传输中?
三、项目拷打
- 缓存系统是本地的吗?怎么实现的?
- LRU 怎么实现?
- LRU-K 相比 LRU 的进阶在哪里?
- 内存泄露怎么解决?
- 了解垃圾回收吗?C++ 为何不做自动 GC?
shared_ptr的引用计数原理是什么?什么时候被清理?- 工作负载剧烈变化的场景是怎么个变化?(项目细节)
- 如果缓存系统加上 TTL,你怎么实现?
- Redis 的 LRU 策略了解吗?
- 缓存击穿是什么?解决方案有哪些?
- QPS 怎么测的?在什么环境下测量的?
- 测 QPS 需要考虑哪些指标?比如 CPU 核数?
- 哈希倾斜了解吗?分片时出现哈希倾斜怎么解决?
- Raft 从哪里学习的?
- MCP 了解吗?SKILL 了解吗?
- 了解哪些分布式一致性算法(Raft、ZAB 等)?
- 哪些场景需要分布式一致性协议?
- Protobuf 和 JSON 在网络传输中怎么抉择?
- CAP 中的一致性和数据库事务的一致性有何区别?
- CAP 的 CA、CP、AP 各自是什么?有哪些代表协议?分别用在哪些场景?
四、学习与成长
- 平时如何学习?当前的学习安排是什么?
五、算法题
-
LeetCode 19:删除链表的倒数第 N 个结点
- 说了思路,面试官追问:可以类比哪种数据结构解决?(答:栈)
-
LeetCode 402:移掉 K 位数字
- 手写,耗时约 15 分钟,部分细节未考虑周全
六、反问环节
- 业务范围是什么?
- 面试官反馈:基础扎实,但项目细节还需深挖。
参考解析
多态的实现机制
- 静态多态:函数重载,编译期决议,通过函数签名区分。
- 动态多态:虚函数 + 虚函数表(vtable)。每个含虚函数的类有一张 vtable,每个对象头部有虚函数指针(vptr)指向该表。运行时通过 vptr 查表调用实际函数,实现派生类覆盖基类行为。
CAS 与 ABA 问题
- CAS(Compare And Swap):原子地比较内存值与期望值,相等则替换为新值,否则失败重试(自旋)。不陷入内核,适合低竞争场景;高竞争时 CPU 忙等待浪费资源。
- ABA 问题:线程 A 读值为 A,期间线程 B 将值改为 B 再改回 A,线程 A 的 CAS 成功但逻辑可能错误。
解法:引入版本号/时间戳,每次修改递增版本,比较时同时校验版本(如AtomicStampedReference)。
TCP 可靠交付机制
- 序列号 + ACK:接收方确认收到的字节范围。
- 超时重传:未收到 ACK 则重传,支持快速重传(收到 3 个重复 ACK)。
- 流量控制:接收窗口(rwnd)告知发送方可接收的数据量。
- 拥塞控制:慢启动、拥塞避免、快恢复,防止网络过载。
LRU 与 LRU-K 实现
- LRU:哈希表 + 双向链表,O(1) 查找与插入。访问时将节点移到链表头,淘汰时删除链表尾。
- LRU-K:数据需被访问 K 次才进入主缓存,冷数据放历史队列,防止偶发性大扫描污染热数据,提升缓存命中率。
shared_ptr 引用计数原理
- 内部维护一个控制块,包含强引用计数和弱引用计数。拷贝时强引用计数 +1,析构时 -1。
- 强引用计数归零时销毁所指对象;弱引用计数也归零时销毁控制块本身。
- 注意:循环引用会导致引用计数永不归零,用
weak_ptr打破循环。
缓存击穿与解决方案
- 缓存击穿:热点 key 过期瞬间,大量请求同时穿透缓存打到数据库。
- 解法:① 互斥锁(只允许一个线程回源,其余等待);② 逻辑过期(不设物理 TTL,由业务层判断并异步更新);③ 提前续期(后台定时刷新热点 key)。
CAP 理论
- C(一致性):所有节点同时看到相同数据(注意:不同于事务 ACID 中的一致性,后者指业务约束不被破坏)。
- A(可用性):每个请求都能收到响应(不保证最新数据)。
- P(分区容忍性):网络分区时系统仍可运行。
- CP:ZooKeeper、Raft(etcd),牺牲可用性保证一致性,适合配置中心、分布式锁。
- AP:Cassandra、Eureka,牺牲一致性保证可用性,适合购物车、DNS。
- CA:单机关系型数据库(不具备分区容忍,实际分布式系统必须选 P)。
Protobuf vs JSON
- Protobuf:二进制编码,体积小(约 JSON 的 1/3~1/5),序列化/反序列化速度快,但可读性差,需要
.proto文件,适合高吞吐内部服务通信。 - JSON:文本格式,可读性好,生态广泛,适合对外 API、调试场景及跨语言兼容要求高的场合。
LeetCode 402:移掉 K 位数字(贪心 + 单调栈)
- 维护一个单调递增栈,遍历每位数字:若当前数字小于栈顶且还能删除(k > 0),则弹出栈顶(k—),将当前数字入栈。
- 遍历结束后若 k > 0,从栈尾再删 k 个。
- 去掉结果的前导零,若为空则返回
"0"。 - 关键细节:前导零处理、k 用完后直接追加剩余数字、结果为空时返回
"0"。