若创科技 智驾系统工程师-C++ 一二面
1. 三个智能指针的区别
答案:unique_ptr 表示独占所有权,同一时刻只能有一个拥有者,开销最小,适合对象边界非常明确的场景。shared_ptr 表示共享所有权,底层靠控制块维护引用计数,适合对象会被多个模块共同持有、释放时机不容易由单方决定的情况。weak_ptr 不拥有对象,只是观察 shared_ptr 管理的对象,主要作用是打破循环引用,或者在不延长对象生命周期的前提下做一次安全访问。真正写工程代码时,优先级一般是值对象 > unique_ptr > shared_ptr,而不是默认无脑上 shared_ptr。
代码:
#include <iostream>
#include <memory>
using namespace std;
struct Node {
int val;
Node(int x) : val(x) {}
~Node() { cout << "~Node\n"; }
};
int main() {
unique_ptr<Node> p1 = make_unique<Node>(1);
shared_ptr<Node> p2 = make_shared<Node>(2);
weak_ptr<Node> p3 = p2;
if (auto sp = p3.lock()) {
cout << sp->val << endl;
}
return 0;
}
2. 怎么通过基类调用派生类成员函数
答案:如果调用的是普通同名成员函数,前提是基类里把它声明成 virtual,然后通过基类指针或引用去调用,这样运行时会根据对象真实类型做动态绑定。如果基类里根本没有这个接口,那基类视角就不知道派生类特有成员,不能直接调。这个时候要么补抽象接口,要么在确定类型安全的前提下做向下转型。面试里这题真正想问的通常不是“会不会写 virtual”,而是你知不知道多态依赖统一接口,而不是靠基类硬调子类私有能力。
代码:
#include <iostream>
using namespace std;
class Base {
public:
virtual void run() { cout << "Base::run\n"; }
virtual ~Base() = default;
};
class Derived : public Base {
public:
void run() override { cout << "Derived::run\n"; }
};
int main() {
Base* p = new Derived();
p->run();
delete p;
return 0;
}
3. 虚函数和多态到底依赖什么机制
答案:核心机制是虚函数表和虚表指针。带虚函数的类通常会有一张虚表,对象内部会有一个隐藏的虚表指针。通过基类指针调用虚函数时,不是在编译期把函数地址写死,而是运行时通过虚表找到真实对象对应的实现。这也是为什么多态一般要求三件事:有继承关系、基类函数是虚函数、通过基类指针或引用调用。另外构造和析构期间的虚函数行为也经常被追问,因为这时对象并不处于“完整派生态”。
4. 内存泄漏一般怎么排查,和野指针、悬空指针有什么区别
答案:内存泄漏是申请的内存失去管理入口,程序之后再也无法释放它;悬空指针是指针还在,但指向的对象已经被释放;野指针则更宽泛,通常指未初始化或已经无效的地址。排查内存泄漏时,本地常用 ASan、LSan、Valgrind,线上则会结合对象计数、内存快照、容器大小、核心路径日志去定位。真正难查的泄漏往往不是忘了 delete,而是全局容器长期持有、回调链没解绑、shared_ptr 循环引用或者异常路径提前返回没走释放逻辑。如果面试继续往下问,通常还会追 RAII、资源所有权设计和内存池。
5. 哈希表的原理是什么,哈希冲突怎么处理
答案:哈希表的核心是通过哈希函数把 key 映射到数组下标,从而尽量做到接近 O(1) 的插入和查询。哈希冲突指不同 key 映射到了同一个桶位置,常见处理方式有拉链法和开放寻址法。C++ 里常见的 unordered_map 更接近桶数组加链式或节点式结构,平均性能很好,但要注意负载因子过高、哈希函数质量差、rehash 带来的性能抖动。如果 key 分布不好或者被恶意构造,哈希表性能会明显下降,所以这题本质上不仅是数据结构题,也带一点工程稳定性思维。
6. unordered_map 和 map 应该怎么选
答案:map 底层通常是红黑树,元素有序,查找、插入、删除复杂度稳定在 O(logn),适合需要有序遍历、范围查询、上下界查找的场景。unordered_map 底层是哈希表,平均查找复杂度接近 O(1),更适合高频按 key 访问。但真正选型时不能只盯复杂度,unordered_map 要考虑哈希冲突、内存占用、rehash,map 则要考虑节点离散、cache 不友好。如果面试官追问工程经验,通常会问迭代器失效、扩容行为和自定义哈希。
7. Linux 修改文件权限常用哪些命令,chmod 777 为什么危险
答案:最常用的是 chmod 改权限、chown 改所有者、chgrp 改组。chmod 777 表示所有用户都有读、写、执行权限,这在绝大多数正式环境里都过于宽松,尤其是脚本、配置、密钥、可执行文件,一旦可被任意用户修改,风险非常大。权限问题本质上考的是最小权限原则,不是“命令会不会背”。如果面试继续问,往往会延伸到 umask、目录权限和特殊位,比如 setuid、setgid、sticky bit。
8. 管道有什么用,匿名管道和命名管道有什么区别
答案:管道本质上是内核提供的一种单向字节流 IPC 机制,常用于把一个进程的输出接到另一个进程的输入。匿名管道通常用于有亲缘关系的进程,比如父子进程,生命周期跟进程关系更紧;命名管道有文件系统路径,没有亲缘关系的进程也可以通过它通信。它们的优点是简单、天然适合流式传输,缺点是消息边界弱、能力有限,不像 socket 那样通用。这题如果往深里问,常会追阻塞语义、半关闭、读端写端关闭后的行为。
代码:
#include <unistd.h>
#include <iostream>
using namespace std;
int main() {
int fd[2];
pipe(fd);
if (fork() == 0) {
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

查看9道真题和解析