百度 C++软件开发 二面 面经
1. shared_ptr 是线程安全的吗?引用计数和对象本身分别是什么情况?
引用计数是线程安全的:
- 控制块中的强引用计数和弱引用计数的增减是原子操作,多个线程同时拷贝或销毁 shared_ptr 不会导致计数错误
对象本身不是线程安全的:
- 多个线程同时读同一个 shared_ptr 对象是安全的
- 多个线程同时对同一个 shared_ptr 对象进行读写(比如一个线程在 reset,另一个在解引用)是未定义行为,需要加锁保护
- shared_ptr 保护的是引用计数,不保护它指向的对象,对象的线程安全需要自己处理
一个常见误区:两个线程各自持有指向同一对象的不同 shared_ptr 副本,并发修改对象内容,这不是 shared_ptr 的责任范围,需要对象自己加锁。
2. 说说 C++ 内存模型中的内存序,relaxed、acquire、release、seq_cst 分别是什么含义?
- relaxed:只保证操作本身的原子性,不提供任何同步和顺序保证,适合只需要计数、不需要同步的场景,性能最高
- release:写操作,保证该操作之前的所有读写不会被重排到它之后,配合 acquire 使用
- acquire:读操作,保证该操作之后的所有读写不会被重排到它之前,配合 release 使用
- release + acquire 配对:线程 A 用 release 写,线程 B 用 acquire 读到该值后,能看到线程 A 在 release 之前的所有写操作,这是最常用的同步手段
- seq_cst:最强的内存序,所有 seq_cst 操作在所有线程中有一个全局一致的顺序,性能最差,是 atomic 操作的默认内存序
实际工程中:实现无锁数据结构时用 acquire/release 精确控制同步点,避免 seq_cst 的全局排序开销。
3. 说说 Linux 虚拟内存机制,mmap 的原理是什么?
虚拟内存:
- 每个进程有独立的虚拟地址空间,通过页表映射到物理内存
- 访问未映射的地址触发缺页异常,内核分配物理页并建立映射
- 写时复制(COW):fork 后父子进程共享物理页,任意一方写时才复制,节省内存
mmap 原理:
- mmap 在进程虚拟地址空间中建立一段映射,可以映射文件或匿名内存
- 映射文件时,读写该内存区域等同于读写文件,内核负责页面换入换出,避免 read/write 的用户态内核态拷贝
- 匿名 mmap 用于大块内存分配,malloc 内部对大于 128KB 的请求就用 mmap
- munmap 释放映射,对于文件映射会将脏页写回磁盘
- 多个进程 mmap 同一文件可以实现共享内存,是高效 IPC 的基础
4. 说说 C++ 模板的实例化机制,什么是模板的二阶段编译?
二阶段编译:
- 第一阶段(模板定义时):编译器检查与模板参数无关的语法错误,比如缺少分号、未声明的非依赖名称
- 第二阶段(模板实例化时):编译器用具体类型替换模板参数,检查依赖于模板参数的代码是否合法
实例化机制:
- 隐式实例化:使用模板时编译器自动生成对应类型的代码,每个编译单元可能各自实例化一份,链接时去重
- 显式实例化:用 template class MyClass<int> 强制在当前编译单元生成实例,其他编译单元用 extern template 声明避免重复实例化,减少编译时间
- 模板代码必须放在头文件中,因为实例化需要看到完整定义,这是模板和普通函数的重要区别
SFINAE(替换失败不是错误):
- 模板参数替换失败时不报错,只是从候选集中移除该重载,配合 enable_if 实现编译期条件选择
5. 说说 TCP 的流量控制和拥塞控制有什么区别?
流量控制:
- 解决的是发送方和接收方之间速度
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++八股文全集 文章被收录于专栏
本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。

查看6道真题和解析