博雷顿科技股份公司 C++ 一面复盘
1. 自我介绍
我之前在某某公司实习,主要参与 C++ 后端相关开发工作。 实习期间参与消息处理和服务端模块开发,涉及功能迭代、问题排查和性能优化。 技术栈以 C/C++ 为主,熟悉 STL、Linux 多线程和网络编程(TCP/IP),了解 MySQL、Redis 组件。 整体偏工程实践,关注代码质量、稳定性及性能优化,期待在 C++ 后端方向继续提升
2. 项目介绍
我参与开发了一个分布式实时流处理平台,负责事件数据的实时计算和多维聚合。项目难点在于高并发写入时线程锁竞争严重,导致延迟不稳定;同时状态同步复杂,内存容易泄漏。
我主要通过以下方式解决了问题:
- 用无锁队列替代传统锁,减少线程竞争。
- 设计分段锁和读写锁,热点数据分离访问。
- 实现轻量快照机制保障状态一致性。
- 优化内存管理,防止碎片和泄漏。
- 使用监控工具定位性能瓶颈并针对性优化。
通过这个项目,我掌握了高性能并发编程和分布式状态管理方法,提升了系统调优和问题定位能力。优化后延迟降低 40%,系统稳定性明显提升。
3. 栈与队列的区别
- 栈(Stack):后进先出(LIFO),只能在栈顶操作。
- 队列(Queue):先进先出(FIFO),元素从尾部入队,头部出队。
4. 栈与堆的区别
- 栈由系统自动管理,空间小,效率高,存储函数调用和局部变量。
- 堆由程序员管理(new/delete 或智能指针),空间大但分配释放开销大。
5. AVL 树
- 一种自平衡二叉搜索树,节点左右子树高度差最大为 1。
- 通过旋转操作维持平衡,保证查找/插入/删除时间复杂度为 O(log n)。
6. map 和 unordered_map
- map 基于红黑树,有序,O(log n) 复杂度。
- unordered_map 基于哈希表,无序,平均 O(1) 复杂度,最坏情况 O(n)。
7. 如何判断链表有环?
- 使用快慢指针(Floyd 判圈算法),快指针每次走两步,慢指针走一步。
- 若快慢指针相遇,则链表存在环;否则无环。
8. 多态的原理
- C++ 运行时多态通过虚函数实现。
- 编译器为虚函数类生成虚函数表(vtable),对象含虚表指针(vptr)。
- 通过基类指针或引用调用虚函数时,动态绑定到派生类实现。
9. 智能指针
- unique_ptr 独占资源所有权,支持移动不支持复制。
- shared_ptr 共享资源所有权,计数管理。
- weak_ptr 弱引用,不增加计数,用于解决循环引用。
10. C++17 新特性
- 结构化绑定(auto [a,b] = ...;)
- if constexpr
- std::optional
- std::variant
- std::string_view
11. 用过哪些容器?
- 顺序容器:vector、deque、list
- 关联容器:map、set、unordered_map、unordered_set
- 容器适配器:stack、queue、priority_queue
12. LRU 缓存设计(代码题)
题目描述 设计并实现一个容量有限的 LRU 缓存:支持 get(key) 和 put(key, value),均需 O(1) 时间复杂度。
关键思路
- 哈希表快速定位缓存项。
- 双向链表维护访问顺序,新访问的节点移动到头部,容量满时淘汰尾部节点。
#include <unordered_map>
#include <list>
class LRUCache {
public:
LRUCache(int capacity): capacity_(capacity) {}
int get(int key) {
auto it = cache_.find(key);
if (it == cache_.end()) return -1;
nodes_.splice(nodes_.begin(), nodes_, it->second);
return it->second->second;
}
void put(int key, int value) {
auto it = cache_.find(key);
if (it != cache_.end()) {
it->second->second = value;
nodes_.splice(nodes_.begin(), nodes_, it->second);
} else {
if ((int)nodes_.size() == capacity_) {
int old_key = nodes_.back().first;
nodes_.pop_back();
cache_.erase(old_key);
}
nodes_.emplace_front(key, value);
cache_[key] = nodes_.begin();
}
}
private:
int capacity_;
std::list<std::pair<int,int>> nodes_;
std::unordered_map<int, std::list<std::pair<int,int>>::iterator> cache_;
};
测试示例
int main() {
LRUCache cache(2);
cache.put(1, 1);
cache.put(2, 2);
std::cout << cache.get(1) << "\n"; // 输出1
cache.put(3, 3); // 淘汰key=2
std::cout << cache.get(2) << "\n"; // 输出-1
cache.put(4, 4); // 淘汰key=1
std::cout << cache.get(1) << "\n"; // 输出-1
std::cout << cache.get(3) << "\n"; // 输出3
std::cout << cache.get(4) << "\n"; // 输出4
return 0;
}
13. 追问
- 构造函数可以是虚函数吗? 不可以,构造函数是在对象创建时调用,没有多态需求,且编译器不支持。
- 析构函数可以是虚函数吗? 可以,基类通常应声明虚析构函数,避免通过基类指针删除派生类对象时资源泄露。
- vector 中可以存 unique_ptr 吗? 可以,但需要用移动语义插入,如 push_back(std::move(ptr)) 或emplace_back()。
14. 反问
问了问团队主要业务方向和技术栈是什么 , 新人前三个月的培训和考核重点如何, 是否有师兄带和代码评审机制 ; 团队性能优化常用哪些工具?排查流程是什么样的?
#有必要和同事成为好朋友吗?#C++面试总结 文章被收录于专栏
本专栏系统梳理C++面试高频考点,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力。

京东工作强度 418人发布