小米汽车 中间件-C++ 一面

1. 自我介绍

2. 你在恒生电子实习学了点什么

3. 智能指针,开发中用过吗

用过,主要接触比较多的是 unique_ptrshared_ptrweak_ptr。在实际开发里,unique_ptr 我一般会用在所有权非常明确的场景,比如某个对象独占一个资源;shared_ptr 更多用于多个模块共享对象生命周期的情况;weak_ptr 则主要用于打破循环引用或者做非拥有式观察。我现在对智能指针的理解不只是“替代裸指针”,更重要的是它把资源归属和生命周期表达得更明确,能减少手动释放资源带来的风险。不过智能指针也不是用了就一定安全,像循环引用、重复托管同一块内存、跨线程访问对象状态这些问题还是要单独注意。

代码:

#include <iostream>
#include <memory>
using namespace std;

class Node {
public:
    Node() { cout << "construct\n"; }
    ~Node() { cout << "destruct\n"; }
};

int main() {
    unique_ptr<Node> p1 = make_unique<Node>();
    shared_ptr<Node> p2 = make_shared<Node>();
    weak_ptr<Node> wp = p2;

    if (auto sp = wp.lock()) {
        cout << "object alive\n";
    }
    return 0;
}

4. unique_ptr 和 shared_ptr 指向同一块内存会有什么问题

如果 unique_ptrshared_ptr 指向同一块通过裸指针分配出来的内存,而且它们彼此不知道对方的存在,那么本质上就是两个独立的所有权管理者在管理同一份资源。这样会导致重复释放。因为 unique_ptr 析构时会删一次,shared_ptr 的引用计数归零时也会再删一次,最终出现 double free,行为未定义。这类问题的根源不是“指针类型不同”,而是同一块内存不能被多个独立所有权体系重复接管。如果对象一开始就准备用共享所有权,那就应该直接用 make_shared 或者明确由 shared_ptr 接管;如果是独占所有权,就只保留 unique_ptr

代码:

#include <memory>
using namespace std;

int main() {
    int* p = new int(10);
    unique_ptr<int> up(p);
    shared_ptr<int> sp(p); // 错误:同一裸指针被两个所有权体系接管
    return 0;
}

5. 同一个裸指针构造两个不同的 shared_ptr 会怎么样,为什么

如果用同一个裸指针分别构造两个不同的 shared_ptr,这两个 shared_ptr 会各自生成独立的控制块,它们的引用计数互不关联。这样表面上看两个 shared_ptr 都在“共享”这块内存,但实际上它们共享的不是同一个控制块。最后两个 shared_ptr 生命周期结束时,都会各自认为自己应该释放对象,于是发生重复释放。正确做法是:一个裸指针只能交给一个 shared_ptr 体系管理,之后其他地方如果也要共享,应该通过拷贝已有的 shared_ptr 来共享控制块,而不是再次从裸指针构造。

代码:

#include <memory>
using namespace std;

int main() {
    int* p = new int(42);
    shared_ptr<int> sp1(p);
    shared_ptr<int> sp2(p); // 错误:两个独立控制块
    return 0;
}

6. shared_ptr 的控制块里通常有什么,如何实现

shared_ptr 底层通常不只是一个裸指针,它还关联一个控制块。控制块里一般会保存几类信息:对象指针或者对象本体、强引用计数、弱引用计数、删除器、分配器等。当强引用计数减到 0 时,对象析构;当强引用和弱引用都为 0 时,控制块本身才释放。从实现角度看,关键是要把“对象生命周期”和“控制块生命周期”区分开。对象可以先销毁,但只要还有 weak_ptr 在观察,控制块就不能立刻没掉。这也是为什么 weak_ptr 能判断对象是否存活,因为它依赖的其实是那份还活着的控制块。

代码:

#include <atomic>
using namespace std;

template <typename T>
struct ControlBlock {
    T* ptr;
    atomic<int> shared_cnt;
    atomic<int> weak_cnt;

    ControlBlock(T* p) : ptr(p), shared_cnt(1), weak_cnt(0) {}
};

7. static 的作用

static 在 C++ 里有几种常见含义。修饰局部变量时,表示这个变量存储期是整个程序运行期,但作用域仍然在函数内部;修饰类成员变量时,表示它属于类本身而不是某个对象;修饰函数或者全局变量时,在当前编译单元内可见,相当于限制链接范围。如果从面试角度讲,我一般会把它总结成两类作用:延长生命周期控制可见性/归属关系。像单例里常见的局部静态对象,就是把生命周期和线程安全初始化一起利用起来。

代码:

#include <iostream>
using namespace std;

void func() {
    static int cnt = 0;
    ++cnt;
    cout << cnt << endl;
}

int main() {
    func();
    func();
    return 0;
}

8. RAII 思想还有哪些应用

RAII 的核心是把资源获取和对象生命周期绑定起来,对象构造时拿资源,对象析构时释放资源。它的应用远不只是智能指针。比如 lock_guardunique_lock管理互斥锁,文件流对象管理文件句柄,数据库连接包装类管理连接,线程封装类管理线程 join/detach,甚至事务回滚保护器本质上也可以看成 RAII。它最大的价值在于异常安全。因为只要对象能正常析构,资源就能自动回收,不容易因为中途 return 或异常抛出导致资源泄漏

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

C++ 常考面试题总结 文章被收录于专栏

本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

全部评论
mark了,这还是小米吗,这么困难啊
点赞 回复 分享
发布于 03-19 22:51 上海
mark
点赞 回复 分享
发布于 03-16 16:03 四川

相关推荐

05-01 17:07
复旦大学 Java
深耕&nbsp;AI&nbsp;辅助开发数月,我也曾一度陷入职业迷茫,甚至动过离开程序员赛道的念头。最开始,我只把&nbsp;AI&nbsp;当作提效利器,由衷惊叹它的强大便捷。可久而久之,过度依赖工具的惯性,慢慢磨掉了我深度钻研技术、独立拆解问题的耐心。日常开发几乎不再手写核心逻辑,大部分工作都交由&nbsp;AI&nbsp;全权承接。和不同岗位的同行交流后才发现,这种状态早已成为常态。前后端、产品、测试,几乎人人都在重度依赖&nbsp;AI&nbsp;赋能工作。难免会生出深深的无力感:看着&nbsp;AI&nbsp;飞速迭代进化,总觉得个人单纯的编码技能正在慢慢弱化,被工具替代的焦虑感时常萦绕心头。但静下心沉淀后才慢慢想通,时代浪潮从不会停下脚步,AI&nbsp;的普及从来不是淘汰从业者,而是筛选更高维度的能力。代码可以被&nbsp;AI&nbsp;生成,逻辑可以被&nbsp;AI&nbsp;补全,但业务洞察力、架构顶层设计、复杂问题统筹拆解、落地复盘沉淀、跨场景资源整合,这些带有人文思考和实战阅历的能力,永远无法被机器简单复刻。底层工具永远会迭代,可人的认知、阅历、决策力和解决复杂非标问题的综合素养,才是普通人立足行业、不可替代的核心价值。不必焦虑内卷,不必畏惧变革。与其被动被&nbsp;AI&nbsp;裹挟,不如主动驾驭&nbsp;AI,把它当作自己的能力延伸,跳出纯编码的底层内卷,向上深耕架构、业务、产品思维,在新的时代风口里,重新找准自己的职业赛道与成长方向。
我的求职进度条
点赞 评论 收藏
分享
评论
点赞
3
分享

创作者周榜

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