面灵AI→

天翼云 C++后端 一面面经:C++ 基础、死锁与内存问题

轮次
一面
时间
2026-09
来源
牛客网

《面试题目》

形式:线上,2 位面试官;无手撕、无笔试。流程:自我介绍 → 面试官一问八股 → 面试官二问项目 → 反问。

  1. struct 和 class 有什么区别?
  2. const 这个关键字的作用是什么?
  3. 重载和重写有什么区别?
  4. 能说一下什么是虚函数吗?
  5. C++ 里内存区域是怎么划分的?
  6. C++ 里智能指针用过吗?
  7. 死锁有哪些必要条件?(追问:互斥是什么意思?)
  8. C++ 里、或者你自己项目里,线程安全问题是怎么处理的?
  9. 除了互斥锁,你有了解过自旋锁或者读写锁吗?
  10. TCP 和 UDP 分别用在什么场景?
  11. 你知道有哪些协议是基于 TCP、哪些是基于 UDP 的吗?(追问:SMTP、Telnet、DHCP)
  12. 说一下什么是内存泄漏?
  13. 虚拟内存存放在哪?
  14. 假设内存耗尽了,你觉得可能会发生什么问题?
  15. 项目这块问了问题定位和程序崩溃调试

反问

《参考解析》

  1. struct 与 class 的差别只有默认权限和默认继承方式:class 的成员与继承默认 private,struct 默认 public,其余能力完全一致。答完可以补一句 C 里的 struct 没有成员函数、也不能有访问控制,把 C 与 C++ 的语境分开,避免被追着问混。再往深可以提 POD 类型与内存布局、标准布局类型对二进制兼容的意义。

  2. 重载、重写、隐藏是三个概念,别只答两个:重载发生在同一作用域,函数名相同、参数列表不同,编译期就完成绑定,返回类型不参与区分;重写是派生类覆盖基类的虚函数,要求签名一致(协变返回类型除外),运行期通过虚表动态绑定;名字隐藏是派生类同名函数把基类一整组函数遮住,需要 using 声明拉回来,这是最容易答错的第三个。

  3. 虚函数与内存分区:虚函数通过对象里的虚表指针找到虚表,再按偏移调用,实现运行期多态;构造函数不能是虚函数,基类析构函数在有通过基类指针删除派生类对象时必须是虚函数。内存分区答栈、堆、全局静态区(已初始化与未初始化)、常量区、代码区,顺带说清栈由高地址向低地址增长、堆反之,以及 new/delete 与 malloc/free 在构造析构上的区别。

  4. 智能指针:unique_ptr 独占所有权、不能拷贝只能移动,开销与裸指针相当;shared_ptr 用引用计数共享所有权,要注意循环引用会泄漏,用 weak_ptr 打破环;weak_ptr 不增加计数,使用前要 lock 提升。追问常接 shared_ptr 的引用计数是不是线程安全的——计数原子但对象本身不是。

  5. 死锁四条件与「互斥」的含义:互斥、占有并等待、不可剥夺、循环等待四个条件同时成立才有死锁。互斥指资源在同一时刻只能被一个执行流持有——它是锁存在的意义,工程上通常无法破坏,所以实际手段落在另外三条:一次性申请全部资源、按全局固定顺序加锁、设置超时与可剥夺(tryLock 失败就释放已持有的锁重试)。

  6. 自旋锁与读写锁的适用边界:自旋锁忙等不睡眠,适合临界区极短且不允许上下文切换的场景,代价是空转 CPU、并且可能出现优先级反转;读写锁适合读多写少,读之间可并发,但写者可能饥饿、而且多数实现不可重入。再补一层线程安全的整体手段:互斥锁、原子操作、无锁队列、把共享状态收敛到单线程处理。

  7. TCP/UDP 场景与协议归属:TCP 面向连接、可靠有序,适合文件传输、HTTP 接口、数据库连接这类不能丢数据的场景;UDP 无连接、开销小、延迟低,适合音视频、游戏、DNS、DHCP。按协议归属答:SMTP、Telnet、HTTP、HTTPS、FTP、SSH 都基于 TCP,DNS、DHCP、TFTP、SNMP 基于 UDP;再加一句 DNS 响应过大或在做区域传送时会退回 TCP,DHCP 走的是 UDP 广播,这两点最容易被追问。

  8. 内存泄漏、虚拟内存与内存耗尽:内存泄漏是申请了内存却不再释放,表现是可用内存持续下降、进程占用只涨不跌。虚拟内存不是「存在某个物理位置」,它是操作系统给进程的地址空间抽象,由页表把虚拟页映射到物理内存页或磁盘交换区,所以答题要落在地址空间加映射机制上。程序不停申请又不释放时,顺序通常是物理内存先耗尽、开始频繁换页导致性能抖动,然后系统扩大页面文件、分配开始失败返回空指针,再恶化就是整机卡死或进程被系统杀掉。