最全【C C++】内存管理,C C++经典面试题详解

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


三、初识

出现了新的关键字:newdelete,它们也有很多形式和使用细节

3.1 new

使用

int\* pi = new int;	//申请一个整型
double\* pd = new double(3.14);	//申请一个浮点型并初始化为 3.14
char\* pc = new char[5] {'H', 'e', 'l', 'l', 'o'};	//申请五个字符型,并分别初始化为 Helloc

注意:

  • newmalloc等不同,不需要进行空指针检查,也不需要进行类型转换
  • new 的使用极其简单

特点:

  • new可以用于自定义类型
  • 动态开辟时,会调用自定义类型的构造函数
//假设存在日期类
Date\* ptr = new Date[5];	//申请五个日期类,这些类都在堆上

下面来看看C++中的内存释放函数

3.2 delete

形式:

  • delete 指针
  • delete[] 指针

使用:

  • C语言中的 free 可以用于释放所有动态申请函数,而 C++ 不行,申请与释放需要配套使用
int\* pi = new int;
delete pi;	//直接释放

double\* pd = new double[5];
delete[] pd;	//释放五次

Date\* ptr = new Date[5];
delete[] ptr;	//释放五次,即调用五次日期类的析构函数

注意:

  • 需要配套使用,new int 搭配 delete,而 new int[] 需要搭配 delete[]

特点:

  • delete可以用于自定义类型
  • 调用销毁时,会先调用自定义类型的析构函数

3.3 特点

C语言C++动态内存管理函数的最大区别是: 是否会调用自定义类型的构造函数和析构函数

C语言明显不会,毕竟那时候还没有这些概念,而 C++ 作为面向对象的语言,调用构造与析构函数是必然的

C语言中的申请函数不能通过C++的释放函数进行释放,同理C++的申请空间也不能通过C语言的释放函数进行释放,比如下面这些情况是不合理的,可能引发问题

int\* cPi = (int\*)malloc(sizeof(int));
delete cPi;	//不合理的操作

int\* cppPi = new int;
free(cppPi);	//这样也是不合理的

Date\* ptr = new Date;
free(ptr);	//此时会报错,因为 free 并不会调用析构函数

切记,申请与释放要配套使用


四、探究

为何C++中的动态内存管理函数能做到调用构造析构函数呢?

  • 这是因为我们也是调用的其他函数,正是得益于C++中的封装

4.1 封装实现

newdelete 是用户进行动态内存申请和释放的 操作符,它们在实现时会去调用真正的全局函数 operator newoperator delete,具体调用情况如下所示:

newnew []

  • new 调用 operator new
  • new [] 调用 operator new[]

deletedelete []

  • delete 调用 operator delete
  • delete [] 调用 operator delete[]

注意: operator new[] 最终是调用 operator newoperator delete[] 最终也是调用 operator delete
所以严格来说,operator newoperator delete 才是我们探讨的主角

所以严格来说,operator newoperator delete 才是我们探讨的主角

4.2 代码展示

/\*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
\*/
void\* \_\_CRTDECLoperatornew(size_tsize)\_THROW1(_STDbad_alloc)
{
	// try to allocate size bytes
	void\* p;
	while ((p = malloc(size)) == 0)
		if (\_callnewh(size) == 0)
		{
			// report no memory
			//如果申请内存失败了,这里会抛出bad\_alloc类型异常
			staticconststd::bad_allocnomem;
			\_RAISE(nomem);
		}
	return(p);
}

可以看到,其实 operator new 就是通过对 malloc 的封装实现的,不过进行了改进,当对象为自定义类型时,会去调用它的构造函数,并且当开辟失败时,会抛出异常

再来看看 operator delete 的代码实现

/\*
operator delete: 该函数最终是通过free来释放空间的
\*/
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 的影子,当释放对象为自定义类型时,会调用它的析构函数


五、new/delete 实现步骤

下面再来看看两者具体的实现步骤

5.1 内置类型

对于内置类型来说,使用 malloc/free 和 new/delete 没什么区别

5.2 自定义类型

对于自定义类型,new/delete 的实现步骤如下:

new

  • 调用 operator new 申请空间
  • 在申请的空间上调用构造函数

delete

  • 在空间上调用析构函数
  • 再调用 operator delete 释放空间

new []

  • 调用 operator new[] 函数,根据数值N,调用N次 operator new 函数申请空间
  • 在申请的空间上调用N次构造函数

delete []

  • 在申请的空间上调用N次析构函数
  • 调用 operator delete[] 函数,然后由函数再调用 operator delete 释放空间

六、定位new

定位newnew 的新用法

目的:

  • 对已开辟而未初始化的空间进行初始化

形式:

  • new(指针)构造函数
//定位new
Stack\* ptr = (Stack\*)malloc(sizeof(Stack));	//malloc 不会调用构造函数,此时未初始化

new(ptr)Stack();	//通过定位new初始化对象

6.1 应用场景

定位new 可以用在内存池这个项目中

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

定位new 可以用在内存池这个项目中

[外链图片转存中…(img-ZwvknDYx-1715820353285)]
[外链图片转存中…(img-oNr9CPwd-1715820353285)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值