优必选 C++开发工程师 二面
1. 常见 STL 容器有哪些?vector/list、map/unordered_map 的区别与使用场景
常见容器:vector、deque、list、set、map、unordered_map、unordered_set、queue、stack。
vector vs list:
- vector 连续内存,随机访问 O(1),尾插高效,cache 友好;
- list 链表结构,任意位置插删 O(1)(已知迭代器),但随机访问差、cache 不友好。
map vs unordered_map:
- map 红黑树,O(logN),有序,可范围查询;
- unordered_map 哈希表,均摊 O(1),无序,最坏可退化。
使用场景:
- 需要顺序、范围查询、稳定复杂度:map;
- 追求高频点查性能:unordered_map;
- 内存局部性和遍历性能优先通常先选 vector。
2. 智能指针:shared_ptr 是线程安全的吗?为什么?
结论分两层:
- 控制块引用计数的增减是线程安全的(通常是原子操作);
- 指向对象本身的读写不是天然线程安全,仍需锁或无锁同步。
另外,同一个 shared_ptr 实例被多线程同时读写(如 reset)也需要外部同步。 所以“shared_ptr 线程安全”只成立在“计数管理”层面,不等于“对象访问安全”。
3. 除了基础单例,如何实现“线程安全 + 防止反序列化破坏”的工程化单例?
推荐“函数内静态对象”(Meyers Singleton),C++11 起初始化线程安全。 如果系统涉及序列化/反射/插件热加载,还要约束拷贝、移动、构造入口。
代码:
class ConfigCenter {
public:
static ConfigCenter& instance() {
static ConfigCenter inst;
return inst;
}
ConfigCenter(const ConfigCenter&) = delete;
ConfigCenter& operator=(const ConfigCenter&) = delete;
ConfigCenter(ConfigCenter&&) = delete;
ConfigCenter& operator=(ConfigCenter&&) = delete;
private:
ConfigCenter() = default;
~ConfigCenter() = default;
};
4. 在“工业 IoT 实时控制网关”项目中你用了哪些容器?为什么这么选?
我在该项目里主要用了:
- vector:存设备连接快照(遍历密集,cache 友好);
- unordered_map:device_id -> session 快速路由;
- deque:收发缓冲队列(头尾操作频繁);
- priority_queue:定时任务超时管理。 选型原则是“访问模式优先”,而不是“容器功能越多越好”。
5. JsonRpc 分层设计如何做,才能支持高并发与可观测?
答案: 可拆为 5 层:
- Transport 层:TCP/WebSocket 收发;
- Codec 层:JSON 编解码与协议校验;
- Dispatcher 层:方法路由、参数绑定;
- Service 层:业务实现与资源访问;
- 治理层:超时、重试、限流、熔断、Tracing。
关键点:
- request_id 全链路透传;
- 错误码分层(协议错误/业务错误/系统错误);
- 与线程模型解耦,避免业务阻塞 IO 线程。
6. muduo 的线程模型和架构是什么?主从 Reactor 相比纯线程池优势在哪?
muduo 典型是 one loop per thread:
- 主 Reactor(acceptor)负责接入;
- 子 Reacto
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++ 常考面试题总结 文章被收录于专栏
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.
字节跳动工作强度 1114人发布
查看3道真题和解析