首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C++内存管理:从malloc到new的进化之路

C++内存管理:从malloc到new的进化之路

作者头像
用户11831438
发布2025-12-30 14:02:43
发布2025-12-30 14:02:43
1520
举报

在学习相关内容之前,我们先来做一道题目:

分析: globalvar是一个全局变量,所以globalvar在静态区;static GlobalVar被static修饰,说明它是一个静态变量,那就在静态区;static Var在静态区;localVar是一个局部变量,局部变量的空间都是在桟帧中开辟的,所以在栈上;num1单独出现,表示数组首元素的地址,那它就是一个指针变量,在栈上;char2表示数组名,为首元素地址,字符串存储在数组中,这个字符串是可以被修改的,那么这个字符串就是在栈上,那char2就在栈上;*char2表示首元素,也在栈上;pchar3是一个指针变量,在栈上;const char* pchar3="abcd"中的const修饰的是指针指向的内容,这个内容不能被修改,这个字符串为常量字符串,在常量区,*pchar3就在常量区;ptr1中存放的是申请空间的地址,是一个指针变量,在栈上;*ptr1表示申请空间的首元素,空间是在堆上申请的,所以*ptr1在堆上。

选择题答案

globalVar在哪里?______ C. 数据段(静态区)

  • 全局变量存储在静态区(数据段)

staticGlobalVar在哪里?______ C. 数据段(静态区)

  • static修饰的全局变量也存储在静态区

staticVar在哪里?______ C. 数据段(静态区)

  • 函数内的static局部变量也存储在静态区

localVar在哪里?______ A. 栈

  • 普通局部变量在栈上

num1 在哪里?______ A. 栈

  • 数组名代表数组首地址,但数组本身在栈上

char2在哪里?______ A. 栈

  • 局部字符数组,整个数组在栈上

*char2在哪里?______ A. 栈

  • 数组首元素在栈上

pChar3在哪里?______ A. 栈

  • 指针变量本身在栈上

*pChar3在哪里?______ D. 代码段(常量区)

  • 指向的字符串"abcd"是常量字符串,在常量区

ptr1在哪里?______ A. 栈

  • 指针变量本身在栈上

*ptr1在哪里?______ B. 堆

  • malloc分配的内存空间在堆上

图示解释:

正文

一、C语言中的内存管理

回顾前面在C语言中的学习,我们学习过malloc/calloc/realloc/free,我们通过题目来回顾一下:

【面试题】

1. malloc/calloc/realloc的区别?

malloc申请空间时不进行初始化,calloc申请空间时自动初始化为0;realloc是对空间的增容:如果原空间后面有空间,那直接在其后面直接扩容,新空间的地址和原空间的地址一样;如果原空间的后面空间不够,则新找一块空间,并将原空间中的数据拷贝到新空间中,再将原空间释放,然后返回新空间的地址

2. malloc的实现原理? glibc中malloc实现原理

其实C语言中的内存管理已经可以解决很多问题,那为什么C++中要搞个新的内存管理呢?ok,通过下面的学习,我们就知道原因了:

二、C++内存管理
2.1 初识new和delete

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式——通过new和delete操作符进行动态内存管理。

2.2 new和delete
2.2.1 new的使用

那这时候就有人想问了,如果我们想要初始化,该怎么做?

2.2.2 delete的使用

delete的使用分为两种情况: 情况1:释放单个

代码语言:javascript
复制
//申请一个int类型的空间,并初始化
int* p3 = new int(10);
//释放单个
delete p3;

情况2:释放多个

代码语言:javascript
复制
//申请一个空间大小为10的数组,int类型,并部分初始化
int* p4 = new int[10] {1, 2, 3, 4};
//释放多个
delete[] p4;

提醒: 释放多个也可以直接写delete p4; 但是不建议这么写

这里博主有一个问题:我们看啊,在C中有申请空间,还有扩容,刚才我们学习C++中的申请空间,那C++中有扩容吗?

其实是没有的,如果需要扩容,自己手动扩

我们看到其实new和delete的功能和malloc、calloc、free的功能很接近,那为什么祖师爷还要搞new和dlete呢?

其实是为了自定义类型,用malloc可以申请一个自定义类型的空间,那该怎么初始化呢?这是不是一个问题,那为了解决这个问题,祖师爷就搞出了new和delete

new和delete就可以解决这样的问题!!!

我们看到:new和delete的最大特点就是自动调用构造和析构,而malloc和free不会!!!以后主要使用new和delete

2.2.3 new delete的失败

new 和 delete也会失败,那他们的失败和malloc free的失败是一样的吗?

其实是不一样的,new申请空间失败不会返回空,而是会抛异常

那我们该怎么捕获异常呢(ok,这里博主简单演示一下,后面会具体介绍):

代码语言:javascript
复制
void func()
{
	int i = 1;
	int* ptr = nullptr;
	do {
		if (i == 495)
		{
			int x = 0;
		}

		ptr = new int[1024 * 1024];
		cout << i++ << ":" << ptr << endl;
	} while (ptr);

	cout << i++ << ":" << ptr << endl;
}
int main()
{
	try
	{
		func();
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}

	return 0;
}

通过上面的try,catch就可以捕获异常。

2.3 new和delete的底层

new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。operator new 和operator delete是系统提供的全局函数

2.3.1 new的底层

new开空间的步骤:

  1. 先调用operaotr new 在堆上开空间(底层还是调用malloc)
  2. 调用构造

先调用operaotr new 在堆上开空间(底层还是调用malloc)——这是什么意思?

我们来看一下底层代码:

代码语言:javascript
复制
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)
		if (_callnewh(size) == 0)
		{
			// report no memory
			// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return(p);
}

operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。

所以说new的底层还是调用malloc,可以认为new是对malloc的包装

2.3.2 delete的底层

delete的步骤:

  1. 调用析构
  2. 调用operator delete
代码语言:javascript
复制
void operator delete(void* pUserData)
{
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK); /* block other threads */
	__TRY
		/* get a pointer to memory block header */
		pHead = pHdr(pUserData);
	/* verify block type */
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK); /* release other threads */
	__END_TRY_FINALLY
		return;
} /
*
free的实现
* /
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

operator delete: 该函数最终是通过free来释放空间的!!!

通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。

三、new和delete的实现原理

new的原理

  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理

  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申
  2. 在申请的空间上执行N次构造函数

delete[]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
四、malloc/free和new/delete的区别

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:

  1. malloc/free是函数,new/delete是操作符
  2. malloc 失败返回的是nullptr,需要我们进行判断;new失败抛异常,不需要进行判断,但要捕获异常
  3. malloc只开空间,不初始化;new开空间,可以初始化
  4. malloc申请空间时需要手动计算空间大小;new只需在其后面跟上类型即可,如果是多个对象,[ ]中指定个数即可
  5. malloc 的返回值类型为void* ,需要强转;new不需要,后面跟的就是类型
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理释放

上面的区别不建议背,理解即可!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-09-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正文
    • 一、C语言中的内存管理
    • 二、C++内存管理
      • 2.1 初识new和delete
      • 2.2 new和delete
      • 2.3 new和delete的底层
    • 三、new和delete的实现原理
    • 四、malloc/free和new/delete的区别
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档