网易 C++ 一面
1. 自我介绍
2. GitHub仓库面试官,点开了之后,夸我对技术积极性比较高, 大致聊了一下
3. 智能指针了解什么?
核心是所有权模型:
- unique_ptr:独占所有权,不能拷贝可移动(默认首选);
- shared_ptr:共享所有权,引用计数管理生命周期;
- weak_ptr:弱引用,不增加计数,用于打破循环引用。 原则:能不用 shared_ptr 就不用,避免不必要原子计数开销。
代码:
std::unique_ptr<int> p1 = std::make_unique<int>(42); std::unique_ptr<int> p2 = std::move(p1); // 所有权转移
4. shared_ptr 的控制块是什么?线程安全吗?
shared_ptr 通常包含两部分:对象本体 + 控制块(强/弱引用计数、删除器等)。
- 引用计数增减一般是线程安全的(原子);
- 对象本身访问是否线程安全,取决于对象自己的同步策略。 所以“shared_ptr 线程安全”不等于“对象线程安全”。
5. 虚函数原理:为什么能调用到具体子类?
因为运行时多态依赖虚表机制:
- 含虚函数的类有虚表(vtable);
- 对象里有虚表指针(vptr);
- 通过基类指针调用虚函数时,运行时根据对象真实类型查表分派到子类实现。
代码:
struct Base { virtual void f(){ } virtual ~Base() = default; };
struct Derive : Base { void f() override { /* 子类实现 */ } };
Base* p = new Derive();
p->f(); // 动态绑定到 Derive::f
delete p;
6. 空类里面有什么?
空类不是 0 字节,通常至少占 1 字节,用于保证不同对象有不同地址。 如果有虚函数,还会有虚表指针成员(对象大小会变大)。
代码:
#include <iostream>
class Empty {};
int main() { std::cout << sizeof(Empty) << "\n"; } // 通常输出 1
7. C++ 内存分区
常见回答:代码区、全局/静态区、堆、栈、常量区。 但工程里更重要的是:
- 谁分配谁释放(或 RAII 托管);
- 生命周期是否跨线程;
- 是否存在悬垂/越界/泄漏风险。
8. new/delete 和 malloc/free 的区别?
- new/delete:C++ 运算符,分配/释放同时会调用构造和析构;
- malloc/free:C 库函数,只管内存,不管对象生命周期。 混用是未定义行为(new 的对象必须 delete)。
代码:
struct A { A(){} ~A(){} };
A* p = new A(); // 调构造
delete p; // 调析构
9. 多线程同步怎么做?手撕条件变量
条件变量用于“等待某条件成立再继续执行”,常与 mutex + unique_lock + predicate 搭配。 关键点:
- 等待必须带谓词;
- 修改条件后要 notify_one/all;
- 条件与共享状态必须同一把锁保护。
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++ 常考面试题总结 文章被收录于专栏
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.
查看9道真题和解析