某日二师兄参加XXX科技公司的C++工程师开发岗位6面:

面试官: 如何在堆上申请一块内存?

二师兄:常用的方法有malloc,new等。

面试官:两者有什么区别?

二师兄:malloc是向操作系统申请一块内存,这块内存没有经过初始化,通常需要使用memset手动初始化。而new一般伴随三个动作,向操作系统申请一块内存,并执行类型的默认构造函数,然后返回类的指针。

面试官:嗯,那你知道calloc和realloc吗?

二师兄:calloc比malloc多做了一步,就是把申请的内存初始化成0。而realloc则可以改变当前指针所指向的内存块的大小。

面试官:好的。那么你知道这些api/操作符失败会发生什么吗?

二师兄:malloc/calloc/realloc失败会返回NULL,而new失败则会抛出异常。

面试官:有没有让new失败不抛出异常的方法?

二师兄:好像有,但是我不记得了。。。

面试官:没关系。。。我们都知道new和delete成对出现,new[]和delete[]也是成对出现,那么我想问,如果使用new[]创建的对象用delete释放了会发生什么?为什么?

二师兄:额。。。内存泄漏?对,会发生内存泄漏。因为内存没有被释放。

面试官:好的。我们都知道C++中的内存管理是一个比较麻烦的事情,现在有个需求,需要在程序中记录主动申请的内存和主动释放的内存,以确保没有发生内存泄漏。有什么好的方法吗?

二师兄:可以重载new和delete运算符。

面试官:如何重载new和delete运算符?

二师兄:我得查一下资料,这个重载用的很少。。。

面试官:(笑)好吧,最后一个问题,咱们上面一直在讨论堆中的内存的分配和释放,请问一下,如果在栈上分配一块固定的内存?栈中的内存如何释放?

二师兄:额。。。(思考)使用 char[size] ? 应该不需要手动释放。

面试官:好的,回去等通知吧。

对于二师兄的表现,小伙伴们能给打几分呢?我们先看看二师兄在面试中表现不太好的地方:

面试官:有没有让new失败不抛出异常的方法?

在C++中我们可以使用以下方法使得new运算符不抛出异常,

int* p = new (std::nothrow) int(42);
if(p == nullptr)
{
//分配失败
}

这个特性需要C++11支持。

再看下一个问题:

如果使用new[]创建的对象用delete释放了会发生什么?

一定会发生内存泄漏吗?答案是,不一定。这取决于类型T。我们先看第一种情况:

class Foo
{
public:
Foo():num_(42){}
private:
int num_;
}; Foo* pf = new Foo[1024];
delete pf;

当类型T没有管理资源时,delete pf会把整个申请的1024个Foo所占用的内存全部归还给操作系统,此时并没有内存泄漏。再看下一种情况:

class Foo
{
public:
Foo():num_(new int(42)){}
~Foo(){delete num_;}
private:
int* num_;
}; Foo* pf = new Foo[1024];
delete pf;

此时会造成内存泄漏,原因很简单。在执行delete[]时,首先逆序执行每个元素的析构函数,然后再把整块内存归还给操作系统。而delete只会把内存还给操作系统,没有执行析构函数。当类没有资源需要管理时,执行与不执行析构函数都无关紧要,但是当类中需要管理资源时,析构函数的执行就至关重要了。

如何重载new和delete运算符?

#include <iostream>
#include <cstdlib>
#include <map>
struct MemoryInfo {
size_t size;
const char* file;
int line;
}; std::map<void*, MemoryInfo> memoryMap; void* operator new(size_t size, const char* file, int line) {
void* ptr = std::malloc(size);
memoryMap[ptr] = {size, file, line};
return ptr;
} void operator delete(void* ptr) noexcept {
auto it = memoryMap.find(ptr);
if (it != memoryMap.end()) {
std::free(ptr);
memoryMap.erase(it);
}
} #define new new(__FILE__, __LINE__) int main() {
int* p = new int(42); for (const auto& [ptr, info] : memoryMap) {
std::cout << "Memory allocated at " << ptr << " with size " << info.size
<< " in file " << info.file << " at line " << info.line << std::endl;
} delete p; for (const auto& [ptr, info] : memoryMap) {
std::cout << "Memory allocated at " << ptr << " with size " << info.size
<< " in file " << info.file << " at line " << info.line << std::endl;
}
return 0;
}

最后一个问题:

如果在栈上分配一块固定的内存?栈中的内存如何释放?

使用alloca,虽然简单,但是很多人可能都没有接触过:

int* p = (int*)alloca(4);
*p = 42;

栈上申请的内存不需要手动释放。注意,如果栈溢出,alloca的行为时未定义的。

好了,今日份面试到这里就结束了,小伙伴们,对于今天二师兄的面试,能打几分呢?

关注我,带你21天“精通”C++!(狗头)

C++面试八股文:如何在堆上和栈上分配一块内存?的更多相关文章

  1. go语言的局部变量在堆上还是栈上?

    在讨论之前,先看如下代码: type treeNode struct { value int left, right *treeNode } func createNode(value int) *t ...

  2. C++如何限制对象在堆上或栈上生成

    1,限制类的对象只能生成在栈上 将 operator new 各种原型设为私有 #include <iostream> class OnlyOnStack { public: OnlyOn ...

  3. 堆(heap)和栈(stack)几点认识

    堆(heap)和栈(stack)主要的区别由以下几点:1.管理方式不同:2.空间大小不同:3.产生碎片不同:4.生长方向不同:5.分配归属不同:6.分配效率不同:7.存取效率不同:管理方式:对于栈来讲 ...

  4. Heap(堆)和stack(栈)有的区别是什么。

    java的内存分为两类,一类是栈内存,一类是堆内存.栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这个 ...

  5. 最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保留一块内存

    申请效率的比较 栈:由系统自动分配,速度较快.但程序员是无法控制的. 堆:是由new分配的内存,最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保 ...

  6. 每日一问2:堆(heap)和栈(stack)的区别

    因为这里没有明确指出堆是指数据结构还是存储方式,所以两个尝试都回答一下. 一.堆和栈作为数据结构 1.堆(heap),也叫做优先队列(priority queue),队列中允许的操作是先进先出(FIF ...

  7. 《面试八股文》之 JVM 20卷

    微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. <面试八股 ...

  8. 《面试八股文》之kafka21卷

    微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是moon,最新一篇面试八股文系 ...

  9. 《面试八股文》之 Redis 16卷

    微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. redis 作为 ...

  10. 一天吃透JVM面试八股文

    什么是JVM? JVM,全称Java Virtual Machine(Java虚拟机),是通过在实际的计算机上仿真模拟各种计算机功能来实现的.由一套字节码指令集.一组寄存器.一个栈.一个垃圾回收堆和一 ...

随机推荐

  1. MySQL 索引的种类

    我们知道一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重. 一.平衡多路查 ...

  2. 在一张 24 GB 的消费级显卡上用 RLHF 微调 20B LLMs

    我们很高兴正式发布 trl 与 peft 的集成,使任何人都可以更轻松地使用强化学习进行大型语言模型 (LLM) 微调!在这篇文章中,我们解释了为什么这是现有微调方法的有竞争力的替代方案. 请注意, ...

  3. Windows10 穿越火线手感和Windows7不一样

    如果是穿越火线或者其他FPS玩家,应该会感觉Win10和WIin7两者手感会有一定的区别.为什么升级了系统变菜了?心理作用?其实确实和系统有关系哦.我从Windows7升级到Windows10玩穿越火 ...

  4. 关于ul点击事件委托给li时的鼠标拖动问题

    网上查看后发现Click可以被两个事件触发:mouseUp与mouseDown,即点击和松开时都会触发一次. 随后当我从一个li点击拖动到其他li松开时,触发的事件对象因为冒泡变成了父元素ul,并非我 ...

  5. 【实战】SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目

    JavaDog Chat v1.0.0 基于SpringBoot+uniapp简单通讯聊天软件 项目介绍 JavaDog Chat 简单通讯聊天软件是基于SpringBoot+MybatisPlus+ ...

  6. 使用 Solon Cloud 的 Jaeger 做请求链路跟踪

    <dependency> <groupId>org.noear</groupId> <artifactId>jaeger-solon-cloud-plu ...

  7. 生产事故-记一次特殊的OOM排查

    入职多年,面对生产环境,尽管都是小心翼翼,慎之又慎,还是难免捅出篓子.轻则满头大汗,面红耳赤.重则系统停摆,损失资金.每一个生产事故的背后,都是宝贵的经验和教训,都是项目成员的血泪史.为了更好地防范和 ...

  8. python中文文档

    这是在线中文文档 https://docs.python.org/zh-cn/3.7/library/winreg.html

  9. 开源项目audioFlux: 针对音频领域的深度学习工具库

    目录 时频变换 频谱重排 倒谱系数 解卷积 谱特征 音乐信息检索 audioFlux是一个Python和C实现的库,提供音频领域系统.全面.多维度的特征提取与组合,结合各种深度学习网络模型,进行音频领 ...

  10. SpringBoot项目中使用缓存Cache的正确姿势!!!

    前言 缓存可以通过将经常访问的数据存储在内存中,减少底层数据源如数据库的压力,从而有效提高系统的性能和稳定性.我想大家的项目中或多或少都有使用过,我们项目也不例外,但是最近在review公司的代码的时 ...