小米 C++ 软件开发 一面 面经

小米一面整体节奏很快,面试官技术功底扎实,问题层层递进,不会只停在概念层面,基本每道题都会追问"为什么"或者"你在项目里怎么用的"。整个面试大概 60 分钟,前半段是基础八股,后半段直接上手撕代码,压力不小但氛围还算友好。建议提前把 C++ 内存模型、并发、STL 底层这几块吃透,代码题要写得干净,边界条件别漏。

1. 自我介绍

略(根据个人情况准备,建议控制在 2 分钟内,突出项目亮点和技术栈)

2. 进程和线程的区别?进程间通信有哪些方式?线程间通信呢?

进程是资源分配的基本单位,线程是 CPU 调度的基本单位。同一进程内的线程共享堆、全局变量、文件描述符,但各自拥有独立的栈和寄存器。

进程间通信(IPC)方式:

  • 管道(pipe):半双工,只能父子进程间用
  • 命名管道(FIFO):可以无亲缘关系进程间通信
  • 消息队列:内核维护的消息链表,支持按类型读取
  • 共享内存:最快的 IPC 方式,需要配合信号量同步
  • 信号量:用于进程/线程间同步
  • Socket:可跨机器通信,最通用

线程间通信相对简单,共享内存天然可见,主要靠 mutex、condition_variable、atomic 来同步。

3. std::movestd::forward 的区别?什么场景下用 forward

std::move 无条件将左值转换为右值引用,触发移动语义,不做任何转发逻辑。

std::forward 是完美转发,保留参数的值类别(左值还是右值)。典型场景是模板函数中:

template<typename T>
void wrapper(T&& arg) {
    // 如果用 move,左值参数也会被当右值传,语义错误
    target(std::forward<T>(arg)); // 正确:保留原始值类别
}

forward 依赖模板类型推导,单独使用没有意义,必须配合万能引用(T&&)。

4. std::shared_ptr 的实现原理?线程安全性如何?循环引用怎么解决?

shared_ptr 内部维护两个指针:一个指向托管对象,一个指向控制块(control block)。控制块里有引用计数(use_count)和弱引用计数(weak_count),用原子操作保证计数本身的线程安全。

但注意:引用计数的增减是线程安全的,但对同一个 shared_ptr 对象的并发读写不是线程安全的(比如两个线程同时对同一个 shared_ptr 变量赋值)。

循环引用:A 持有 B 的 shared_ptr,B 持有 A 的 shared_ptr,导致引用计数永远不为 0,内存泄漏。解决方案是将其中一方改为 weak_ptrweak_ptr 不增加引用计数,使用时调用 lock() 获取临时 shared_ptr

5. volatile 关键字的作用?它能保证线程安全吗?

volatile 告诉编译器不要对该变量做优化,每次读写都直接访问内存,防止编译器将其缓存在寄存器中。

典型场景:内存映射 IO、硬件寄存器访问、信号处理函数中修改的变量。

不能保证线程安全。volatile 只阻止编译器优化,不提供原子性,也不产生内存屏障。多线程场景应该用 std::atomic 或 mutex。

6. 什么是内存对齐?为什么需要内存对齐?如何手动控制结构体的内存对齐?

内存对齐是指数据存储的起始地址必须是其大小的整数倍。比如 int(4字节)的地址必须是 4 的倍数。

原因:

  • CPU 访问对齐的数据只需一次总线操作,非对齐可能需要两次,性能差
  • 某些架构(如 ARM)直接不支持非对齐访问,会触发硬件异常
struct A {
    char a;   // 1 byte + 3 padding
    int  b;   // 4 bytes
    char c;   // 1 byte + 3 padding
};
// sizeof(A) = 12

#pragma pack(1)  // 取消对齐,按1字节紧凑排列
struct B {
    char a;
    int  b;
    char c;
};
// sizeof(B) = 6
#pragma pack()

// 或者用 alignas
struct alignas(16) C { int x; };

7. 虚函数表是什么?多重继承下虚函数表结构是怎样的?

每个含虚函数的类都有一张虚函数表(vtable),存放虚函数指针数组。每个对象头部有一个 vptr 指向该表。调用虚函数时通过 vptr 找到 vtable,再找到对应函数指针,实现运行时多态。

多重继承下,派生类会有多个 vptr,每个基类对应一张 vtable。比如:

class A { virtual void f(); };
class B { virtual void g(); };
class C : public A, public B { void f() override; void g() override; };

C 的对象布局中有两个 vptr,分别对应 A 和 B 的 vtable。调用 ((B*)c)->g() 时会用第二个 vptr。这也是为什么多重继承下指针转换可能会调整地址偏移(thunk 机制)。

8. std::unordered_mapstd::map 的底层实现及时间复杂度对比

底层结构

红黑树

哈希表(链地址法)

查找

O(log n)

平均 O(1),最坏 O(n)

插入

O(log n)

平均 O(1)

有序性

有序

无序

内存

较少

较多(桶数组)

unordered_map 最坏 O(n) 发生在哈希冲突严重时(比如所有 key 哈希到同一个桶)。自定义类型作 key 需要提供 hash== 运算符。

9. std::vector 的扩容机制?扩容代价多大?如何避免频繁扩容?

vector 容量不足时,通常按 2 倍(GCC)或 1.5 倍(MSVC)扩容:分配新内存 → 移动/拷贝旧元素 → 释放旧内存。

扩容代价:O(n) 时间,所有迭代器、指针、引用全部失效。

避免频繁扩容:

  • 提前 reserve(n) 预分配容量
  • 如果知道大概大小,构造时传入 size
  • emplace_back 代替 push_back 减少拷贝

10. 什么是虚假共享(False Sharing)?如何避免?

多个线程访问不同变量,但这些变量恰好在同一个 CPU 缓存行(通常 64 字节)内,导致一个线程修改自己的变量时,另一个线程的缓存行也被

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++八股文全集 文章被收录于专栏

本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。

全部评论
厉害啊,整理的这么给力的
点赞 回复 分享
发布于 04-12 14:23 陕西

相关推荐

03-24 16:25
湖南大学 Ruby
春招接连栽在AI面试上,好几次都是AI评分太低,直接没进一面,踩完坑总算摸透了AI面的套路,特意整理出来,和同样碰壁的牛友们交流讨论⚠️&nbsp;核心认知:AI面是程序,不是真人面试官千万别把AI当成真人聊天,它的评分机制特别程序化,对语速、语言逻辑、表达流畅度要求极高,绝对不能即兴发挥、想到哪说到哪。平时跟真人面试的松弛感,放在AI面里只会直接拉低分数,必须针对性调整答题方式。⚙️&nbsp;看懂AI面试内部实现逻辑AI面评分主要分两步,一步错就全盘拉胯:一是语音转文字,对语速要求很苛刻,语速太快、太慢、卡顿结巴,都会导致转写错误,文字错了后续得分直接崩盘;二是文字得分判断,核心考察语言逻辑性,不会共情也不会体谅即兴发挥,语言组织混乱、没有条理,就算内容再好也拿不到高分。🎯&nbsp;AI面试核心得分点:只认程序化逻辑AI不会看你的真情实感,只抓关键词和逻辑结构,这是拿分关键:✅&nbsp;优先用STAR法则、总分总这类固定框架,AI对标准化结构敏感度极高;✅&nbsp;多用逻辑衔接词:首先、其次、最后、第一、第二、第三,靠这些词强行拉满逻辑感,得分会明显更高;✅&nbsp;提前备好岗位核心关键词,答题时自然嵌入,AI抓取到关键词就会加分;✅&nbsp;语速必须均匀流畅,不卡顿、不重复、不忽快忽慢,保证语音转写零失误。💡&nbsp;个人实战心得:把AI当应试机器人,背稿应试才是王道AI就是个死板的程序,没有人情味,越按固定流程答题,越容易拿高分。别把它当人沟通,就当成一台应试机器、一道客观题,针对性钻它的程序化漏洞就行。既然它只认关键词和逻辑顺序,那咱们就提前把高频题的答案完整组织好,熟练背熟,模拟练习到语速均匀、表达流畅,就像玩动作游戏背BOSS出招表一样,摸透规则对症下药,通过率直接翻倍,亲测有效!
AI面会问哪些问题?
点赞 评论 收藏
分享
评论
1
7
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务