C++动态内存管理 解剖new/delete详细讲解(operator new,operator delete)

在这里插入图片描述
讨厌抄我作业和不让我抄作业的人
讨厌插队和不让我插队的人
讨厌用我东西和不让我用东西的人
讨厌借我钱和不借给我钱的人
讨厌开车加塞和不让我加塞的人
讨厌内卷和打扰我内卷的人

一、C++中动态内存管理

1.new和delete操作内置类型

2.new和delete操作自定义类型

二、operator new与operator delete函数

三、operator new[]与operator delete[]函数

四、new和delete的实现原理

五、完结撒❀

–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–

一、C++中动态内存管理

我们在C语言中所学习的动态内存函数:malloc,calloc,ralloc这些在C++中也可以继续进行使用,但是使用起来比较麻烦,并且一些地方留有不足,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

再强调一次:new和delete是两个操作符

1.new和delete操作内置类型

操作方式如下:

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr1 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr2 = new int(10);
  
  // 动态申请10个int类型的空间
  int* ptr3 = new int[10];
  
  //delete完成空间的销毁
  delete ptr1;
  delete ptr2;
  //销毁连续多个空间
  delete[] ptr3;
}

new和delete对动态内存开辟的操作就是这么朴实无华。

在这里插入图片描述这里注意一下初始化开辟的一个空间数据用(),开辟多个空间内存用[ ],初始化开辟的多个空间类型数据用{},操作如下:

int* ptr0 = new int[10] {1, 2, 3, 4, 5};
delete[] ptr0;

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。

2.new和delete操作自定义类型

操作如下:

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}

	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};
int main()
{
	// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
	A* p1 = (A*)malloc(sizeof(A));
	A* p2 = new A(1);
	free(p1);
	delete p2;

	// 内置类型是几乎是一样的
	int* p3 = (int*)malloc(sizeof(int)); // C
	int* p4 = new int;
	free(p3);
	delete p4;

	A* p5 = (A*)malloc(sizeof(A) * 10);
	A* p6 = new A[10];
	free(p5);
	delete[] p6;
	return 0;
}

大家可以运行上面代码,研究观察new和delete与malloc和free的区别。

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

二、operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符operator new和operator delete是系统提供的全局函数new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

我们针对代码转到反汇编就可以看到:

在这里插入图片描述
而对于operator new其底层实现是通过malloc函数实现的,operator delete其底层是通过free实现的

见下图:

在这里插入图片描述
在这里插入图片描述这里的_free_dbg表示的就是free,因为free函数是一个宏:

#define   free(p)       _free_dbg(p, _NORMAL_BLOCK)

不仅从汇编我们可以认识operator new函数和operator delete函数,我们还可以看一下其是如何实现的:

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空               间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
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 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 new函数和operator delete函数的实现代码大家简单看一下,理解即可,看不懂没有关系

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

三、operator new[]与operator delete[]函数

我们在开辟多个类型数据时用new T[N],其内部调用的是operator new[]函数,而operator new[]函数其实就是由operator new函数实现完成的,见下面汇编代码:

在这里插入图片描述

在这里插入图片描述
同理delete[]函数内部实现是由operator delete[]函数实现的,而operator delete[]函数内部实现也是由operator delete函数所实现的:

在这里插入图片描述
在这里插入图片描述

operator new[]函数内部实现逻辑由operator new函数实现,那么为什么还需要operator new[]函数呢?

在上面的学习中,我们强调过new和delete配对使用,而new[]要和delete[]进行配对使用,new[]和delete[]是在创建多个类型数据时进行使用,这里对于内置类型来说的话其实没多大意义(因为内置类型不需要调用构造函数和析构函数),主要在自定义类型上面

new和delete在创建和销毁自定义类型分别会自动调用构造函数和析构函数,所以我们在创建多组自定义类型数据时需要根据自定义类型的个数来确定一共需要调用几次构造函数和析构函数

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << this << endl;
	}

	~A()
	{
		cout << "~A()" << this << endl;
	}
private:
	int _a;
};

int main()
{
	A* ptr1 = new A; //operator new + 1次构造
	A* ptr2 = new A[10];//operator new[] + 10次构造

	delete ptr1;//1次析构 + operator delete
	delete[] ptr2;//10次析构 + operator delete

	return 0;
}

而调用operator new[]函数就实现了对类型数据个数的存储,我们可以看下代码:

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a = 0)" << this << endl;
	}

	~A()
	{
		cout << "~A()" << this << endl;
	}
private:
	int _a;
};

int main()
{
	A* ptr1 = new A[3];

	delete[] ptr1;

	return 0;
}

按照正常计算的话,new开辟A[3]其大小应为12字节,但是我们转到汇编代码:

在这里插入图片描述
会发现一共是16个字节,这里多出来的4个字节就是用来存储总数据个数所用的。

同理,对于operator delete[]函数也一样,operator new[]函数记录了所创建的总数居的多少,也是为下面operator delete[]函数调用多少次析构函数做铺垫。

对于operator delete[]函数,最后也会在内存空间中会向前偏移4个字节的位置再进行free,将所存储数据个数的4个字节一同free掉。

四、new和delete的实现原理

1.内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL

2.自定义类型

· new的原理

1. 调用operator new函数申请空间

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

· delete的原理

1. 在空间上执行析构函数,完成对象中资源的清理工作

2. 调用operator delete函数释放对象的空间

· new T[N]的原理

1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请

2. 在申请的空间上执行N次构造函数

· delete[N]的原理

1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理

2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释
放空间

通过上面的学习我们可以发现,对于操作符,其内部都是由一条一条指令进行实现的,所以我们使用操作符 ,在编译器编译时就会将操作符转换成每一条指令执行。

五、完结撒❀

如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友❤
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/552115.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人生的关键在于思想、精神和心情

人生的关键在于思想、精神和心情&#xff0c; 努力让自己的思想明澈&#xff0c; 让自己的精神充实而有所支撑&#xff0c; 让自己每天都有一个豁达、平和、开朗的心情&#xff0c; 这很重要。

SQLite的知名用户(二十九)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite作为应用程序文件格式&#xff08;二十八&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 SQLite被数以百万计的应用程序使用 从字面上看&#xff0c;有数十亿次部署。 SQLite 是 当今世界。 下面显示了一些…

Taro-vue微信小程序用户隐私保护

Taro-vue微信小程序用户隐私保护 一、在 微信公众平台的【设置】- 【服务内容与声明】 &#xff0c;设置用户隐私保护指引&#xff0c;添加项目需要的接口权限。 【用户隐私保护指引】提交之后&#xff0c;官方会进行审核。审核通过之后&#xff0c;对应的接口权限才会生效。 …

实现 Table 的增加和删除,不依赖后端数据回显

需求 删除前 删除后 分析 首先写一个 Table <a-card style"width:100%"><template#extra><a-button type"text" click"addSelectItem" style"margin-right: 5px">添加</a-button><a-button type&quo…

springboot源码解析(一):启动过程

springboot源码解析(一):启动过程 1、springboot的入口程序 SpringBootApplication public class StartupApplication {public static void main(String[] args) {SpringApplication.run(StartupApplication.class, args);} }当程序开始执行之后&#xff0c;会调用SpringAppli…

大话设计模式之单例模式

单例模式是一种创建型设计模式&#xff0c;它确保类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。 单例模式通常在以下情况下使用&#xff1a; 当一个类只能有一个实例&#xff0c;并且客户端需要访问该实例时。当该唯一实例需要被公开访问&#xff0c;以便在…

2022年团体程序设计天梯赛-总决赛 L1 -L2

目录 L1-1 今天我要赢 L1-2 种钻石 L1-3 谁能进图书馆 L1-4 拯救外星人 L1-5 试试手气 L1-6 斯德哥尔摩火车上的题 L1-7 机工士姆斯塔迪奥 L1-8 静静的推荐 L2-1 插松枝 L2-2 老板的作息表 L2-3 龙龙送外卖 L2-4 大众情人 L1-1 今天我要赢 分数 5 2018 年我们曾经出…

新游戏-开箱H5游戏【无限贝拉/疯狂骑士团】最新整理Linux手工服务端+详细搭建教程

小编教大家搭建游戏啦 一款H5奉上 先上图 然后再看教程 90GM基地&#xff1a;www.t1gm.com 默认解压密码&#xff1a;www.t1gm.com 本教程只限于技术研究使用&#xff0c;请勿用于商业用途。 本资源由90GM基地独家提供 90GM基地交流群&#xff1a;639140260 ★★★★…

朗思-我的家园正式上线:朗思科技Agent工具软件--人人拥有“Ai-机器人”

4月16日&#xff0c;朗思科技正式发布"朗思-我的家园"。朗思科技是国内领先的Ai Agent智能自动化工具软件产品及方案的提供商&#xff0c;始终坚持自主研发&#xff0c;全面支持国产信创&#xff0c;不断加快产品创新迭代。基于技术领先性和战略前瞻性&#xff0c;其…

MySQL Explan执行计划详解

Explan执行计划 首先我们采用explan执行计划 执行一条sql&#xff0c;发现返回了12个列&#xff0c;下面会详细解释每一列 1、ID列 id列的值是代表了select语句执行顺序&#xff0c;是和select相关联的&#xff1b;id列的值大的会优先执行&#xff0c;如果id列为空最后执行&a…

用html画一个睡觉的熊动画

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>睡觉的熊动画</title><link rel"stylesheet" href"./style.css"> </head><body><div id"contain…

通过抖音短视频获客 只需要六步

抖音是当前最受欢迎的短视频平台之一&#xff0c;拥有庞大的用户群体和强大的社交矩阵&#xff0c;已经成为企业打造品牌口碑和快速获客的一种有效方式。那么&#xff0c;如何利用抖音短视频快速获客&#xff0c;打造品牌口碑呢&#xff1f;小马识途营销顾问简要分析如下&#…

Vue+OpenLayers7入门到实战:OpenLayers加载wkt格式数据,OpenLayers解析wkt格式的要素数据并渲染到地图上

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7入门到实战 前言 本章介绍如何使用OpenLayers7在地图上加载并解析wkt格式数据,以及渲染wkt格式的要素数据到地图上的功能。 使用Point(点)、(LINESTRING)线,和(POLYGON)多变形的wkt数据进行演示。 wkt介绍请参考博主…

【模拟】Leetcode 提莫攻击

题目讲解 495. 提莫攻击 算法讲解 前后的两个数字之间的关系要么是相减之差 > 中毒时间 &#xff0c;要么反之 那即可通过示例&#xff0c;进行算法的模拟&#xff0c;得出上图的计算公式 class Solution { public:int findPoisonedDuration(vector<int>& time…

论文DOI号相关及在latex中添加DOI跳转

DOI与ISBN, ISSN的不同之处 图书和期刊内容都使用DOI。 与ISBN和ISSN不同的是&#xff0c;ISBN喝ISSN可以识别图书或期刊&#xff0c;DOI可以识别单个章节或单篇文章。 所以&#xff0c;如果要搜寻某本书籍&#xff0c;需要用到的是ISBN号&#xff1b;如果要搜寻某本期刊&…

ESXi 无法启动NTP守护进程

在VMware ESXi环境中如果遇到无法启动NTP&#xff08;Network Time Protocol&#xff09;守护进程的问题&#xff0c;可以通过以下步骤进行排查和解决&#xff1a; 步骤1&#xff1a;检查与修复配置文件 登录到ESXi Shell&#xff08;SSH&#xff09;。编辑 /etc/ntp.conf 配…

Boost电感的作用

Boost电感在Boost升压电路中起着关键的作用。Boost电路是一种DC-DC电源转换器&#xff0c;其主要功能是将低电压直流&#xff08;DC&#xff09;信号转换为高电压直流&#xff08;DC&#xff09;信号。Boost电感在这个过程中起着平滑电流、储存能量和提高电路效率的作用。 具体…

C++初级----list(STL)

1、 list介绍 1.1、 list介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 1. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向 其前一…

文件操作;

目录 1.文件的打开与关闭&#xff1b; 打开文件&#xff1b; 关闭文件&#xff1b; 2.文件的打开方式&#xff1b; “r”&#xff08;只读&#xff09;&#xff1b; “w”&#xff08;只写&#xff09;&#xff1b; 3.文件的顺序读写&#xff1b; 字符输入函数fgetc 代…

【智能排班系统】Quartz结合Cron-Utils自定义时间发送上班、休息提醒

文章目录 Quartz&#xff1a;强大的Java作业调度引擎Quartz概述核心概念与架构配置文件主配置&#xff08;配置主要调度器设置、事务&#xff09;线程池配置&#xff08;调整作业执行资源&#xff09;SimpleThreadPool特定属性自定义线程池 RAMJobStore配置&#xff08;在内存中…