吐血整理|C++大厂高频考点汇总
备战了几个月,刷了几十套大厂面经,把C++方向的高频考点全部整理出来了。华为、大疆、字节、地平线、海康、商汤、百度、腾讯、阿里,这些公司的C++面试题我基本都过了一遍,发现考来考去就是那些核心知识点。
这篇文章把最高频的考点全部列出来,每个点都标注了考察频率,帮你把有限的时间花在刀刃上。
一、内存管理(必考,几乎100%)
堆和栈的区别
- 栈:编译器自动管理,速度快,大小有限(默认8MB),局部变量和函数调用信息存这里
- 堆:手动管理(new/delete),大小受限于系统内存,灵活但容易泄漏
内存布局(必须背下来)
- text段:代码,只读
- rodata段:字符串常量、const变量
- data段:已初始化的全局/静态变量
- BSS段:未初始化或初始化为0的全局/静态变量,不占可执行文件空间
- heap:向高地址增长
- stack:向低地址增长
内存对齐
- 每个成员按自身大小对齐
- 结构体整体大小是最大成员的整数倍
- 大成员放前面可以减少padding,节省内存
- #pragma pack(n)强制按n字节对齐,用于网络协议包
智能指针(高频)
- unique_ptr:独占所有权,零开销,不能拷贝只能移动
- shared_ptr:共享所有权,引用计数,make_shared一次分配对象和控制块
- weak_ptr:不增加引用计数,打破循环引用,访问前需要lock()
- 循环引用是shared_ptr最常见的坑,A持有B的shared_ptr,B持有A的shared_ptr,两者永远不析构
二、面向对象(必考)
虚函数机制
- 每个含虚函数的类有一张vtable,存放虚函数指针
- 每个对象头部有vptr指向所属类的vtable
- 调用虚函数:通过vptr找vtable,通过偏移找函数指针,间接调用
- 开销:每个对象多一个vptr(8字节),每次调用多一次间接寻址,无法内联
继承和多态
- 析构函数必须声明为virtual,否则通过基类指针delete派生类对象会内存泄漏
- override关键字:显式标记重写,编译器检查基类是否有对应虚函数,防止拼写错误
- 纯虚函数:
= 0,抽象类不能实例化,用于定义接口规范
构造和析构顺序
- 构造:基类先于派生类,成员变量按声明顺序
- 析构:顺序完全相反
- 成员变量的构造顺序和初始化列表的顺序无关,只和声明顺序有关,这是常见的坑
拷贝控制(三五法则)
- 需要自定义析构函数时,通常也需要自定义拷贝构造和拷贝赋值
- C++11加上移动构造和移动赋值,合称五法则
- 现代C++推荐用RAII封装资源,让编译器自动生成正确的拷贝/移动语义
C++面试常考题目类型都放入了专栏了:https://www.nowcoder.com/creation/manager/columnDetail/Mq7XWW
三、移动语义和右值引用(高频)
左值和右值
- 左值:有名字、有持久地址,可以出现在赋值号左边
- 右值:临时的、没有持久地址,通常是字面量、临时对象、函数返回的非引用值
std::move和std::forward
- std::move:无条件转成右值引用,不做任何运行时操作,只是static_cast
- std::forward:有条件转发,只在推导出右值引用时才转成右值,用于完美转发
- 用错的坑:在转发函数里用move而不是forward,会把传进来的左值强转成右值,调用方的对象被意外移走
移动语义的价值
- 移动构造函数"窃取"临时对象的资源,O(1)完成,而拷贝是O(n)
- 移动构造函数要声明noexcept,否则vector扩容时不会使用移动,退化成拷贝
- RVO/NRVO:编译器直接在目标位置构造对象,省略拷贝,C++17强制保证RVO
四、模板和泛型编程(中高频)
模板基础
- 函数模板:编译器根据实参自动推导类型
- 类模板:使用时必须显式指定类型(C++17的CTAD可以省略)
- 模板定义必须放在头文件,因为实例化发生在调用点
模板特化
- 全特化:为特定类型提供完全不同的实现
- 偏特化:只对部分参数特化,如对所有指针类型特化
- 函数模板不支持偏特化,用函数重载替代
C++17实用特性
- if constexpr:编译期条件分支,替代复杂的enable_if,可读性大幅提升
- std::optional:明确表达"可能没有值"的语义,替代返回-1或nullptr
- std::variant:类型安全的union,配合visit做模式匹配
- std::string_view:只读字符串视图,不拷贝数据,解析场景性能提升明显
- 结构化绑定:
auto [key, value] = *map.find(k),遍历map更简洁
五、STL容器(必考)
vector
- 扩容机制:size等于capacity时,重新分配(通常1.5倍或2倍),移动所有元素,旧内存释放
- 扩容时所有迭代器和指针失效
- 优化:提前reserve避免多次扩容;元素类型提供noexcept移动构造;用emplace_back替代push_back
map vs unordered_map
- map:红黑树,O(log n),有序,稳定
- unordered_map:哈希表,平均O(1),无序,最坏O(n)(哈希冲突)
- 选择:需要有序遍历用map;纯查找性能优先用unordered_map,但要用好的哈希函数
unordered_map的坑
- 负载因子超阈值触发rehash,O(n)操作,造成偶发性延迟,提前reserve避免
- 哈希碰撞攻击:恶意构造大量相同哈希的key,退化成O(n),安全场景用带随机种子的哈希函数
string的SSO
- 小字符串优化:短字符串(通常15字节以内)直接存在string对象内部,不堆分配
- 这是为什么sizeof(string)通常是32字节而不是24字节
六、并发编程(高频)
内存序(大厂必问)
- relaxed:只保证原子性,不提供同步,适合纯计数器
- acquire/release:配对使用,建立happens-before关系,是无锁编程的标准手段
- seq_cst:最强,全局顺序一致,代价最高
- x86上release/acquire几乎免费,ARM上会生成真实的内存屏障指令
shared_ptr的线程安全
- 引用计数的增减是线程安全的(原子操作)
- shared_ptr对象本身不是线程安全的,多线程同时读写同一个shared_ptr实例有数据竞争
- 多个线程各自持有自己的shared_ptr副本是安全的
常见同步原语
- mutex:保护临界区,配合lock_guard/unique_lock使用
- condition_variable:等待/通知,必须配合unique_lock,等待用while循环防虚假唤醒
- atomic:单变量原子操作,无锁,性能最好
- shared_mutex(C++17):读写锁,读多写少场景
thread_local
- 每个线程有独立副本,线程创建时初始化,线程销毁时析构
- 典型用途:每线程的错误码、随机数生成器状态、内存池、日志缓冲区
七、RAII和异常安全(中高频)
RAII核心思想
- 构造时获取资源,析构时释放资源,资源生命周期和对象生命周期绑定
- C++保证局部对象在离开作用域时一定调用析构函数(无论正常返回还是异常抛出)
- 这是实现异常安全基本保证的基础
异常安全三个级别
- 基本保证:不泄漏资源,对象处于有效状态
- 强保证:操作要么完全成功要么完全回滚(copy-and-swap惯用法)
- 不抛出保证(noexcept):析构函数、移动操作应该尽量达到这个级别
八、编译链接(中频)
静态链接 vs 动态链接
- 静态链接:库代码直接复制到可执行文件,自包含,体积大,多个程序各有一份
- 动态链接:运行时加载,多个程序共享同一份库的物理内存,节省内存
- PLT/GOT延迟绑定:第一次调用时解析真实地址,后续直接跳转,加快启动速度
ABI稳定性
- C++ ABI不稳定,不同编译器/版本可能不兼容
- 动态库对外只暴露C接口(extern "C"),C没有name mangling,ABI稳定
- 这是为什么很多SDK用C接口而不是C++接口
九、大厂真实考察重点
根据我整理的面经,不同公司的侧重点:
华为:内存管理、多线程、Linux系统编程,问得很细,喜欢追问底层原理
大疆:实时系统、性能优化、内存序,会问嵌入式场景下C++的限制
字节:模板元编程、移动语义、并发编程,喜欢问"为什么"和"有什么坑"
地平线:自动驾驶场景下的C++,实时性、内存管理、零开销抽象
海康:音视频场景的C++,零拷贝、性能优化、多线程
商汤/寒武纪:AI推理场景,内存布局、SIMD、编译器优化
十、备战建议
优先级排序(按考察频率)
必须掌握:内存管理、虚函数机制、移动语义、智能指针、STL容器、多线程基础
重点掌握:模板特化、异常安全、内存序、编译链接
了解即可:协程、模板元编程、ABI
学习方法
光看不够,要能说出来。每个知识点练习用自己的话解释清楚,面试时才能流畅表达。
八股文要和项目结合。面试官问虚函数,你能结合自己项目里的多态设计来回答,比背书有说服力得多。
追问要准备好。大厂面试官不会只问表面,每个知识点都要准备"为什么"和"有什么坑"的回答。
查看6道真题和解析