三七互娱 游戏开发-C++ 一面

1. 自我介绍

2. 这两个项目是你自己写的吗?

3. 指针和引用的区别是啥?

核心区别

(1)引用底层实现

语法层面引用是“变量别名”,底层编译器通过指针实现:

  • 编译时会为引用分配与指针相同的内存(如64位系统8字节),存储绑定变量的地址;
  • 运行时访问引用等同于通过指针解引用访问原变量(如int &a = b; a = 10;等价于int *p = &b; *p = 10;);
  • 区别仅在于编译器做了语法约束(如强制初始化、禁止修改指向),无额外性能开销。

(2)引用作为函数返回值的风险

风险点:

  1. 返回局部变量的引用:局部变量存在栈上,函数结束后栈帧销毁,引用指向非法内存(野引用);示例:int& func() { int a = 10; return a; } → 调用func()后引用指向已释放的栈空间;
  2. 返回临时对象的非const引用:临时对象生命周期仅在表达式内,引用悬空。

正确场景:

  • 返回类成员变量的引用(如std::string& operator[](int idx));
  • 返回全局/静态变量的引用。

4. 栈内存和堆内存的分配和释放

核心区别

(1)堆申请空间是真实内存还是虚拟内存

堆申请的是虚拟内存:

  • 操作系统为进程分配虚拟地址空间(如64位系统48位虚拟地址),new/malloc仅在虚拟地址空间中标记一段地址为“已分配”;
  • 只有当程序首次访问该虚拟地址时,操作系统才会通过MMU(内存管理单元)将虚拟地址映射到物理内存(真实内存),触发“缺页中断”;
  • 虚拟内存的优势:进程间地址隔离、突破物理内存大小限制。

(2)new和malloc的区别

(3)堆内存碎片化的原因及解决方案

碎片化原因:

  • 频繁申请/释放不同大小的堆内存块,导致内存空间被分割为大量不连续的小空闲块(外部碎片);
  • 内部碎片:分配的内存块大于实际需求(如malloc按8字节对齐,申请1字节会分配8字节)。

解决方案:

  1. 内存池:预分配大块连续堆内存,划分为固定大小的内存块,统一管理申请/释放,减少系统调用和碎片;
  2. 内存对齐:按固定大小(如16字节)分配,减少内部碎片;
  3. 碎片整理:空闲时合并相邻空闲块(内存池的“内存合并”逻辑);
  4. 使用智能指针:减少手动释放导致的内存块零散问题。

5. 怎么避免内存泄漏

核心方法

  1. 使用智能指针:替代裸指针管理堆内存,自动释放;
  2. 遵循RAII原则:将资源(内存/文件句柄/锁)封装到类中,构造时申请,析构时释放;
  3. 工具检测:用Valgrind、AddressSanitizer、Visual Leak Detector排查泄漏;
  4. 规范编码:配对使用new/delete、new[]/delete[],避免重复释放/悬空指针;
  5. 内存池:统一管理堆内存申请/释放,减少零散内存块。

(1)RAII思想 -> 智能指针

  • RAII(资源获取即初始化)核心:将资源的生命周期与对象绑定,对象创建时获取资源,对象销毁时自动释放资源;
  • 智能指针是RAII的典型实现:封装裸指针,析构函数中调用delete释放内存,无需手动管理。
① 智能指针有几种,有什么特点
② shared_ptr的循环引用是怎么回事
  • 循环引用场景:A的shared_ptr指向B,B的shared_ptr指向A → 双方引用计数互锁(均为1),析构时计数无法归0,对象无法释放,导致内存泄漏;
  • 解决方法:将其中一方的shared_ptr改为weak_ptr(如B中用weak_ptr<A>指向A),weak_ptr不增加引用计数,外部释放后计数可归0。
③ 智能指针和裸指针有什么优缺点
④weak_ptr的lock()方法返回空的场景及处理
  • lock()返回空的场景:weak_ptr观察的对象已被销毁(shared_ptr引用计数为0);
  • 处理方式:调用lock()前先通过expired()判断对象是否存活;lock()返回shared_ptr后判空,再访问对象,避免空指针访问:
std::weak_ptr<Obj> wp = ...;
if (auto sp = wp.lock()) { // lock()返回shared_ptr,非空则对象存活
    sp->do_something();
} else {
    // 处理对象已销毁的逻辑
}

6. C++的多态是怎么实现的

C++多态分为静态多态(编译期) 和动态多态(运行期):

(1)模板+函数重载(静态多态)

  • 函数重载:同一作用域内函数名相同、参数列表不同,编译器根据实参类型在编译期绑定函数;
  • 模板:template <typename T> T add(T a, T b),编译器根据传入类型实例化不同版本,编译期确定调用;
  • 核心:编译期确定调用的函数,无运行时开销。

(2)继承+虚函数

  • 实现步骤:父类声明虚函数(virtual void func());子类重写虚函数(void func() override);父类指针/引用指向子类对象,运行期调用子类重写的函数;
  • 底层原理:编译器为含虚函数的类生成虚表(vtable)(存储所有虚函数地址);类对象包含虚表指针(vptr),指向所属类的虚表;运行期通过vptr找到对应类的vtable,调用重写后的虚函数。

(3)虚函数存放在哪里

  • 虚函数的代码存放在代码区(text段)(与普通函数一致);
  • 虚函数的地址存放在虚表(vtable) 中,虚表属于类级别的数据,存放在全局/静态区(data段);
  • 虚表指针(vptr)存放在对象的内存布局中(通常是对象的第一个成员)。

(4)虚析构函数的底层原理及不写虚析构的坑

  • 底层原理:析构函数声明为virtual后,会被加入虚表;子类重写析构函数(编译器自动处理),运行期通过虚表调用子类析构函数,保证“先析构子类、再析构父类”。
  • 不写虚析构的坑:父类指针指向子类对象时,析构仅调用父类析构函数,子类析构函数不执行 → 子类资源泄漏(如子类堆内存未释放)
class Base { ~Base() {} }; // 非虚析构
class Derived : public Base { int *p = new int; ~Derived() { delete p; } };
Base *ptr = new Derived();
delete ptr; // 仅调用Base::~Base(),Derived的p未释放,内存泄漏

7. 用过什么排序或者你最常用的排序是什么

(推荐回答:快速排序,兼顾性能和实用性)我最常用的是快速排序,其次是归并排序和插入排序(小规模数据)。

(1)快速排序的原理是什么,简要说明一下

核心是“分治思想”,步骤:

  1. 选基准:从数组中选一个元素作为基准(pivot,通常选首/尾/中间元素);
  2. 分区:遍历数组,将小于基准的元素放到左区间,大于基准的放到右区间,基准归位;
  3. 递归:对左右区间重复上述步骤,直到区间长度为1(有序)。

(2)快速排序的最坏时间复杂度及优化方案

  • 最坏时间复杂度:​(如数组已排序,选首元素为基准,分区后左区间为空,右区间n-1个元素);
  • 优化方案:基准优化:选“首+中+尾”三个元素的中位数作为基准;小规模数据优化:区间长度小于10时,改用插入排序(避免递归开销);三路快排:将数组分为“小于基准、等于基准、大于基准”三部分,避免重复元素导致的性能退化;随机选基准:随机选取基准元素,降低最坏情况概率。

8. 设计模式用过哪些?

(推荐回答:创建型+结构型各1-2个,突出落地场景)我用过创建型的单例模式、简单工厂模式,结构型的适配器模式:

  • 单例模式:用于内存池、日志器(全局唯一实例);
  • 简单工厂模式:用于TCP服务器的客户端连接处理(根据协议类型创建不同的处理类);
  • 适配器模式:适配不同版本的第三方库接口。

(1)单例模式是怎么实现的

单例模式核心是“保证类仅有一个实例,提供全局访问点”,主要有两种实现:

  1. 饿汉模式:
class Singleton {
private:
    static Singleton instance; // 程序启动时初始化(全局区)
    Singleton() = default; // 私有化构造
    Singleton(const Singleton&) = delete; // 禁用拷贝
    Singleton& operator=(const Singleton&) = delete; // 禁用赋值
public:
    static Singleton& getInstance() { return instance; }
};
Singleton Singleton::instance; // 类外初始化

2. 懒汉模式:

class Singleton {
private:
    static std::unique_ptr<Singleton> instance;
    static std::mutex mtx;
    Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
public:
    static Singleton& getInstance() {
        if (!instance) { // 第一次检查(减少锁

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

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

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

全部评论
感谢分享,沾点喜气!
点赞 回复 分享
发布于 02-27 21:36 四川
虚表我记得存储在只读数据段吧
点赞 回复 分享
发布于 02-27 20:23 重庆

相关推荐

不愿透露姓名的神秘牛友
03-23 10:00
小鹏汽车 采购 16.5Kx(13-15) 大专
点赞 评论 收藏
分享
作为一名双非院校的应届生,在求职面试这场竞争里,我一开始满是自卑。看着身边985、211的同学轻松拿到面试邀约,我投出的简历大多石沉大海,好不容易争取到面试机会,还总担心学历成为短板,被面试官直接否定。但前后经历12场面试,从紧张到从容,我最终拿下了2家心仪企业的offer,也摸索出双非生专属的面试技巧与干货,今天就以我的真实经历,分享面试遇到的问题、回答经验,帮所有双非同学打破学历枷锁,靠实力逆袭。一、双非生面试核心原则:扬长避短,用优势盖过学历短板面试前我就想明白,双非院校的学历没法改变,与其纠结,不如把面试官的注意力从学历转移到我的能力、态度、匹配度上。面试官招的是能干活的人,不是只看学历的标签,尤其是中小企业、优质私企,更看重实操能力和性价比,这就是我们双非生的突破口。我总结了两个核心原则:一是绝不主动提学历,被问到也不卑不亢;二是所有回答都紧扣岗位需求,用经历说话,用细节打动面试官。全程保持自信,眼神坚定、表达流畅,哪怕学历不占优,专业、靠谱的状态也能加分不少。二、我的真实面试高频问题+满分回答(双非直接套用)这些都是我面试中反复遇到的问题,针对双非生的痛点打磨了回答,不踩坑、不露怯,还能凸显优势:1.&nbsp;自我介绍(面试第一题,决定第一印象)踩坑回答:我是XX学校XX专业的学生,成绩一般,没什么实习经历,希望能得到这个机会。我的满分回答:面试官您好,我是XX,毕业于XX院校XX专业,虽然我的院校背景不算突出,但我一直针对性深耕目标岗位,在校期间系统学习了XX专业知识,还通过实习掌握了XX技能,能熟练使用XX办公/专业工具。之前在XX实习中,独立完成了XX工作,帮团队提升了XX效率,我做事踏实、学习能力强,非常贴合贵司岗位的要求,也渴望能在这里沉淀成长,希望您能给我一个机会。技巧:不提学历劣势,重点讲技能、实习、态度、匹配度,简洁有力,1分钟说完。2.&nbsp;你觉得自己的院校背景,相比其他求职者有什么优势?送命题,双非必被问踩坑回答:我学历不好,但我很努力。我的满分回答:我深知院校背景不是我的优势,所以我比很多人更看重实操和积累,在校期间没浪费时间,一直针对性补充岗位所需的技能和实习经验,做事更踏实、更有责任心,不会眼高手低。而且我学习能力很强,入职后能快速上手工作,稳定性也更高,我相信能力和态度,比院校标签更能胜任岗位。技巧:不回避学历,转而强调踏实、学习力、稳定性、实操经验,让面试官看到你的态度。3.&nbsp;你对我们公司了解多少?为什么选择这个岗位?高频题,考察诚意和匹配度我的回答:我关注贵司很久了,了解到贵司主营XX业务,在行业内口碑很好,而且公司注重员工培养,发展平台很稳定。我应聘的XX岗位,和我的专业、实习经历高度匹配,我擅长的XX技能刚好能用到岗位上,我也非常认同公司的企业文化,希望能加入团队,用自己的能力为公司创造价值,同时也能在岗位上深耕学习。技巧:提前查公司业务、岗位要求,不说空话,体现诚意和提前准备。4.&nbsp;你最大的缺点是什么?避坑题,别踩雷我的回答:我觉得我最大的缺点是经验不够丰富,所以面对复杂问题时,会提前做好规划、多请教前辈,避免出错。现在我也一直在积累实操经验,慢慢提升自己的独立处理问题的能力。技巧:说无关痛痒、可改进的缺点,不说懒惰、粗心等致命问题,同时体现改进态度。5.&nbsp;你还有什么要问我的?收尾题,别冷场我的回答:请问这个岗位的日常工作内容主要有哪些?团队目前最需要新人解决的问题是什么?您觉得胜任这个岗位,最重要的能力是什么?技巧:不问薪资、加班,问岗位内容、工作要求,体现对岗位的重视。三、双非生面试必学技巧,全是实战干货1.&nbsp;提前模拟,克服紧张双非生面试容易紧张,我会提前把高频问题写下来,对着镜子反复练习,纠正语速、神态,也会找朋友模拟面试,提前适应节奏,避免面试时大脑空白。2.&nbsp;简历是底气,一定要精准优化面试的核心是围绕简历,双非生简历本来没优势,绝不能写得流水账。我一开始的简历全是大白话,实习经历写得像打杂,面试时面试官根本没兴趣深挖。后来用泡泡小程序AiCV简历王优化简历,彻底改变了局面。这个小程序能精准对标岗位JD,把我普通的校园经历、零散的实习内容,用专业话术包装,量化工作成果,还把岗位核心关键词融入简历,让面试官一眼看到我的匹配度。原本平平无奇的简历,变得亮眼又专业,面试时面试官全程围绕简历提问,我也能从容应对,这也是我能逆袭的关键。3.&nbsp;突出实操能力,少说空话面试官不爱听虚的,双非生要多讲做过什么、怎么做的、结果如何,用具体案例说话。比如不说“我会做运营”,而说“我实习时负责社群运营,拉新XX人,活跃度提升XX%”,用事实证明能力。4.&nbsp;态度真诚,礼貌加分面试时主动问好、离场致谢,认真倾听面试官的问题,回答时真诚不浮夸。双非生的真诚和踏实,是很多面试官看重的品质,比刻意装大神更讨喜。5.&nbsp;避开学历雷区绝不抱怨学校、不贬低自己,被问到学历时,淡定回应,快速转移到能力话题,不纠结、不内耗。四、写在最后:双非生,面试不用怕经历这么多场面试,我终于明白,双非不是求职的死刑,学历只是一块敲门砖,真正决定面试结果的,是你的能力、态度、准备程度。我们或许起点不高,但只要找对方法、充分准备,把每一次面试都当成实战,用实力弥补学历差距,照样能拿到心仪的offer。希望所有双非的同学,都能摆脱学历自卑,掌握这些面试技巧和真题回答,优化好简历,从容面对每一场面试,成功逆袭上岸!
查看5道真题和解析
点赞 评论 收藏
分享
评论
4
21
分享

创作者周榜

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