小米 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。

全部评论

相关推荐

压力很大,面试官全程高压,问的问题不难,但是没有任何反馈,很慌张,也无算法。实习问了20分钟,一直问我你们做的有什么用,总时长一小时1.学校都有什么课程2.spring的ioc原理以及优点3.除了解耦还知道什么?4.springboot与spring区别,二者的源码看过没?Tomcat了解嘛?有没有具体看过5.spring的bean,面试官一直在重复一个思想问我懂不懂,完全没听过6.mybatis是干什么的?ibatis用过没?平常怎么写SQL?完全不写嘛?7.设计一个分布式双十一秒杀系统(前端,网关,缓存,数据库防超卖全设计)8.怎么做限流9.缓存与数据库一致性,你做异步要用户等你嘛?10.负载均衡怎么做11.多数据中心还是单数据中心,如果出现没卖完怎么做(到这完全不会了,面试官直接说换个话题吧)12.平常读书吗?13.上过哲学课嘛?14.兴趣爱好有没有15.对ai的看法16.来深圳有问题嘛?17.为什么不考研18.上大学带给了你什么?你提升在哪里,有没有具体的例子?反问:1.现在手机都有应用市场,应用宝怎么盈利?除了手机应用市场还是有人用,现在在做跨端,微软都有合作,之后会进军mac,主要做游戏,腾讯本身就是游戏大户。2.面试表现?整体评价一下会给到反馈。面完直接变HR面,今天HR面后,已经转为录用评估了,来牛客许个愿,暑期现在还没什么面试,希望能拿个offer之后再考虑要不要留在手子吧。
nunuking:三面压力这么大吗,面试的会议约了多长时间呀
面试问题记录
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

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