蓝芯机器人 C++开发 一面

1、讲讲 C++ 动态内存分配

答案:C++ 里的动态内存分配主要指在程序运行过程中按需从自由存储区申请内存,而不是在编译期就把对象大小和生命周期完全定死。最常见的方式就是 new/deletenew[]/delete[],更工程化一点就是通过智能指针、容器和分配器来管理。

从过程上看,动态内存分配通常分成两层:一层是“拿到原始内存”,另一层是“在这块内存上构造对象”。new 会先调用底层的 operator new 分配足够大小的原始内存,再调用构造函数初始化对象;delete 则反过来,先调用析构函数,再调用 operator delete 释放原始内存。

和 C 里的 malloc/free 相比,C++ 动态内存分配更强调对象语义,而不只是字节块。malloc 只管给一块内存,不会构造对象;new 不只是分配,还会完成初始化。

实际开发里,如果直接手写 new/delete 很多,就容易出现泄漏、悬空指针、重复释放,所以现代 C++ 更推荐容器和智能指针来接管大部分动态内存场景。

代码:

#include <iostream>
using namespace std;

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

int main() {
    A* p = new A;   // 分配内存 + 调用构造
    delete p;       // 调用析构 + 释放内存
    return 0;
}

2、new 的底层

答案:new 本质上不是单纯的库函数,而是一个运算符。它底层通常做两件事:先通过 operator new 申请原始内存,再在那块内存上调用构造函数。

比如这句:

A* p = new A();

大致可以理解成下面这样的过程:

void* mem = operator new(sizeof(A));
A* p = new(mem) A();

也就是说,operator new 负责分配内存,真正的对象构造是在这块内存上完成的。如果构造函数抛异常,编译器还会自动调用 operator delete 把刚才那块内存释放掉,防止泄漏。

继续往下说,operator new 默认实现一般会向堆申请内存,申请失败时默认抛出 std::bad_alloc。如果用户自己重载了类内 operator new,那这个类的对象分配策略也可以被定制,比如对象池、小块内存池、对齐分配。

代码:

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

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

    void* operator new(size_t sz) {
        cout << "custom operator new, size = " << sz << endl;
        return ::operator new(sz);
    }

    void operator delete(void* ptr) {
        cout << "custom operator delete\n";
        ::operator delete(ptr);
    }
};

int main() {
    A* p = new A;
    delete p;
}

3、介绍一下智能指针,然后详细讲一个最常用的

答案:智能指针本质上是用 RAII 思想封装资源管理,把“对象什么时候释放”这件事交给对象生命周期,而不是交给人工记忆。常见的有三种:

  • unique_ptr:独占所有权,不能拷贝,只能移动
  • shared_ptr:共享所有权,靠引用计数管理对象生命周期
  • weak_ptr:弱引用,不拥有对象,主要用来观察 shared_ptr 管理的对象并打破循环引用

如果详细讲最常用的,我会讲 shared_ptr。因为它既常用,也最容易被问深。

shared_ptr 的核心不只是“能共享”,而是它背后有一个控制块。这个控制块里通常会存:

  • 强引用计数
  • 弱引用计数
  • 删除器
  • 分配器信息
  • 被管理对象地址或者对象构造信息

每拷贝一次 shared_ptr,强引用计数加一;每析构一个 shared_ptr,强引用计数减一;当强引用计数变成 0,对象析构;当弱引用计数也归零时,控制块本身才释放。

它的好处是多个模块之间可以共享同一个对象,不用人工协调释放时机。但问题也很明显:

  • 有额外计数开销
  • 有控制块内存开销
  • 容易循环引用
  • 以为“有 shared_ptr 就线程安全”其实是误解

代码:

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

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

int main() {
    shared_ptr<A> p1 = make_shared<A>();
    cout << p1.use_count() << endl;

    {
        shared_ptr<A> p2 = p1;
        cout << p1.use_count() << endl;
    }

    cout << p1.use_count() << endl;
    return 0;
}

4、weak_ptrshared_ptr 和普通 new 出来的空间有什么区别,make_shared 做了什么

答案:普通 new 出来的空间,本质上只是你手里拿到一个裸指针,生命周期完全靠你自己管理。它没有引用计数、没有控制块、没有自动释放,也没有弱引用概念。

shared_ptr 则不同。它除了指向对象本身,还会关联一个控制块,控制块记录引用计数等元信息。也就是说,shared_ptr 管理的不是“一个裸地址”这么简单,而是“对象 + 一套所有权管理机制”。

weak_ptr 不拥有对象,它不增加强引用计数,只是指向同一个控制块。所以它和 shared_ptr 的关系更像是“我知道这个对象可能存在,但我不负责让它活着”。访问时要先通过 lock() 尝试提升成 shared_ptr,如果对象已经销毁,lock() 会得到空指针。

make_shared 的关键点在于它通常会做一次更高效的联合分配,把“控制块”和“对象本体”尽量放在一块连续内存里,这样比 shared_ptr<T>(new T) 少一次独立分配,缓存局部性也更好。而 shared_ptr<T>(new T) 常见情况是:

  • new T 分配对象
  • shared_ptr再单独

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

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

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

全部评论

相关推荐

04-03 17:32
已编辑
门头沟学院 Java
看到好多人在吵学历和实习哪个重要,我说下我的经历吧。双非一本,计算机,选了游戏方向。大学没去外面实习过,就是跟着老师做项目,一个Unity的游戏,做了大概一年多。代码写得很烂,但好处是啥坑都踩过:资源加载慢、内存崩、打包黑屏、字体丢失、安卓适配各种奇怪问题。我说一个可能对你有用的点:“每次踩坑我都会记下来”,不是写博客那种正经文章,就记在备忘录里,大概格式:“问题现象→搜了什么关键词→试了哪几种方案→最后怎么解决的”。面试前翻一遍,面试官问项目细节的时候,我能说出具体例子,不像背的。你们可以试试,真的有用。大四投腾讯实习,本来没抱希望。结果简历过了,我当时都觉得是HR手滑了。面试的时候,面试官追着问项目细节:“你这个bug怎么发现的”“为什么这么修”“还有其他方案吗”。我答得磕磕巴巴,但因为有那个备忘录,能说出真实的过程。后来进去之后问过leader,他说当时就是觉得我“确实亲手写过代码,不是那种只做课设的”。另一个可能对你有用的点:简历上别写“熟悉Unity”“负责核心模块”这种空话。我写的是“解决了切后台再回来游戏卡死的问题,原因是静态变量没重置,通过XXX修复”。面试官说他看到这种具体的问题描述,才会觉得你是真的干过。进了实习,发现周围全是92的,就我一个双非。前两周特别自卑,被mentor说过好几次。但我发现一个事:那些92的同学不太愿意做杂活。比如修老bug、写单测、整理文档。我不挑,给我我就做。有一次一个线上bug卡了两天没人接,我说我试试,搞了三天搞出来了。leader没说啥,但后来转正答辩的时候提到了这件事。第三个点:如果你学历不占优,进去之后别想着做大事,先把脏活干好。干一个就记录一个,每周跟leader同步一次你做了什么、解决了什么问题。这样他至少觉得你靠谱。最后转正了。但我真不觉得是“实习吊打学历”,我觉得就是运气好+组里缺人+我愿意干脏活。如果让我重新来一次,我不一定能进得去。说真的,你们身边有没有像我这样学历一般但运气好的?或者学历好但秋招翻车的?另外,我之前整理的面试问题和那个备忘录模板,有需要的可以私信我,我发你,免费的,不是广告。顺便给同样双非、也想冲大厂实习的同学几点实在的建议,都是我踩过的坑:1.&nbsp;别在大二就死磕大厂实习,先去小厂攒经验。我大二投过网易、完美世界,简历直接挂。后来先去了一家做棋牌的小公司(很low,但真能干活),干了一个暑假,把Git、打包、接SDK这些流程跑通了。这段经历写在简历里,后面投腾讯的时候才有的写。2.&nbsp;简历上别写“熟悉”和“了解”,写“我解决了什么问题”。&nbsp;你写“熟悉Unity”,面试官看都懒得看。你写“解决了一个切后台崩溃的问题,原因是XX没重置”,他才会觉得你是个干活的人。3.&nbsp;面试的时候,不会的问题直接说不会,别编。我面试被问到渲染管线,我直接说“这块我没深入做过,我只知道大概流程,具体细节我不清楚”。面试官反而点点头,然后问我项目里的东西。你编的话,他追问两句你就露馅了。4.&nbsp;如果你现在大三还没有实习,别慌,把课程项目做成一个“能给人演示的东西”。&nbsp;录一个视频,或者搞一个简单的网页demo,把链接放简历里。我当时就是把那个Unity游戏录了个屏,大概3分钟,面试官看了之后说“虽然UI很丑,但功能还挺全”。5.&nbsp;运气真的很重要,所以要多投。**&nbsp;我投了大概30多家,只有腾讯一家给了面试。如果我只投了5家,就没有后面的事了。所以不要因为被拒几次就怀疑自己,可能就是岗位不匹配或者人家不缺人。就这些吧。我也是普通学生,不是什么大佬,这些建议也不一定对所有人都适用。如果你有什么自己的经验或者想问的,评论区聊聊。
GymBeast3:过来人说句实话:学历决定你能去什么层级的公司,实习决定你能不能拿到 offer
学历VS实习,哪个更重要...
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

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