【浅谈 new 与 delete】

news2024/11/16 20:04:30

目录:

  • 前言
  • new 与 delete
    • 内置类型
    • 自定义类型
    • operator new 与 operator delete
    • new 和 delete 实现原理
    • 定位new
  • 总结

前言

打怪升级:第39天
在这里插入图片描述

在C语言中,我们动态申请内存的方法是使用malloc函数,它的同胞兄弟还有calloc 和realloc,
与它们配套使用的释放内存的操作为free函数;
因为c++是兼容c的,所以这些函数在c++中是同样可以使用的,那既然如此,
c++为何还要大费周章地去再增添两个新的操作符来完成“原本就可以完成的工作”呢?

C语言是一个面向过程的语言,而c++虽然脱胎与c语言,但它是属于面向对象的,虽然有相同之处,但是c++相对C语言又添加
了太多的新内容,而C语言之中的一些东西虽然可以用,但是已经无法满足我们的使用需求,因此,c++又引入了new 和 delete 两个新的操作符来进行动态内存管理。

new 与 delete

内置类型

  • new使用示例
	//	内置类型
void Test01()
{
	int* p1 = new int;  // 动态申请1个int的空间

	int* p2 = new int(10);  // 动态申请1个int的空间 , 并初始化为 10

	int* p3 = new int[5];  // 动态申请10个int的空间 - 数组

	int* p4 = new int[5] { 0 }; // 动态申请10个int的空间, 并且全部初始化为 0 


	//  注意看new的使用语法,
}

在这里插入图片描述

  • delete使用示例
//	内置类型
void Test01()
{
	int* p1 = new int;  // 动态申请1个int的空间

	delete p1;       //  释放一个空间

	int* p3 = new int[5];  // 动态申请10个int的空间 - 数组

	delete[] p3;     //   释放一个数组

}

在这里插入图片描述

  • new 和 malloc 对比
//	new  和  malloc对比

void Test01()
{
	int* p1 = new int;  
	delete p1;     

	int* p2 = (int*)malloc(sizeof(int));
	free(p2);
	

	int* p3 = new int[5];  
	delete[] p3;    

	int* p4 = (int*)malloc(sizeof(int) * 5);
	free(p4);
}

在这里插入图片描述

  • new初始化
void Test01()
{
	int* p1 = new int(10);  

	int* p2 = (int*)malloc(sizeof(int));
	

	int* p3 = new int[5] { 1, 2 };  

	int* p4 = (int*)malloc(sizeof(int) * 5);
}

在这里插入图片描述


自定义类型

在上面我们可以发现,对于自定义类型的申请空间 new和malloc的差别并不算大,也就是new在写法上方便一些,
而如果仅仅是为了方便一点点就去写出一个新的操作符未免有些大材小用了,
new和malloc真正的区别在于对自定义类型数据申请空间上:

class Date
{
public:
	Date(int year = 2023, int month = 3, int day = 11)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

private:
	int _year;
	int _month;
	int _day;
};

void Test02()
{
	Date* p1 = new Date;

	Date* p2 = (Date*)malloc(sizeof(Date));
	
	delete(p1);
	free(p2);
}

在这里插入图片描述

我们继续看下面一个例子:

class Stack
{
public:
	Stack(int capacity = 8)
	{
		cout << "Stack(int)" << endl;

		_a = new int[capacity] {0};
		_size = 0;
		_capacity = capacity;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;

		delete[] _a;
		_a = nullptr;
		_size = _capacity = 0;
	}

private:
	int* _a;
	int _size;
	int _capacity;

};

void Test03()
{
	Stack* p1 = new Stack;

	Stack* p2 = (Stack*)malloc(sizeof(Stack));

	delete p1;
	free(p2);

}

在这里插入图片描述

new 和 delete 自动调用默认构造和析构函数。
在这里插入图片描述

因此我们要注意:new 和 malloc 最大的区别就是: new 和 delete会自动调用自定义类型的默认构造和析构函数,malloc 和 free 不会。


operator new 与 operator delete

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

 //  下方是截取的 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 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常
operator delete 最终是通过free来释放空间的

补充: operator new 和 operator delete函数 并不是重载 new 和 delete运算符,只是!只是“碰巧”取了这么个名字罢了,
至于为什么取的这么个具有误导性的名字,只有“天知道”,可能是由于外国人起名字的一种习惯,也可能是当时编写该函数的大佬的恶趣味罢,这里可是“绊倒了”一批又一批的c++学子,那么我们现在知道它们不是运算符重载即可。


new 和 delete 实现原理

  • 内置类型

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

  • 自定义类型

new的原理

  1. 调用operator new函数申请空间,operator new 内部使用 malloc;
  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来释 放空间。

定位new

定位new(placement-new)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

  • 使用格式:
    new (place_address) type或者new (place_address) type(initializer-list)
    place_address必须是一个指针,initializer-list是类型的初始化列表

  • 使用场景:
    定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,
    需要使用new的定位表达式进行显示调构造函数进行初始化。

class A
{
public:
	A(int a = 10)
		: _a(a)
	{}

	~A()
	{}

private:
	int _a;
};

void Test04()
{
	A* p1 = new A;

	A* p2 = (A*)operator new(sizeof(A));
	new(p2)A;

	A* p3 = (A*)malloc(sizeof(A));// p3现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
	new(p3)A;                    //  定位new会去调用自定义类型的构造函数

	A* p4 = (A*)malloc(sizeof(A));

}

在这里插入图片描述


总结

没有太多需要注意的,大家一定一定配对使用。


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

php使用tcpdf,通过html生成的pdf文件,合同章(图片)错位?需要怎么解决

php使用tcpdf&#xff0c;通过html生成的pdf文件&#xff0c;合同章有错位&#xff1f;需要怎么解决&#xff1f; 1、html下的排版正确&#xff0c;如图&#xff1a; 2、html代码&#xff0c;如图 3、生成pdf后的文件&#xff0c;如图 $pdf->Image()&#xff0c;计算一下x、…

【QT】详细介绍Qt的窗口属性:Qt::WA_DeleteOnClose属性

目录 1. close()2. WA_DeleteOnClose属性3. 测试3.1 设置了 Qt::WA_DeleteOnClose 属性3.2 未设置 Qt::WA_DeleteOnClose 属性 4. 测试代码 1. close() 当我们创建一个窗口&#xff08;MainWindow, Widget, Dialog, QMessageBox, 等等&#xff09;后&#xff0c;我们一般会调用…

matlab绘制折线图基本操作

本篇博客主要总结matlab绘制折线图的基本操作&#xff0c;使用的函数是plot函数&#xff0c;关于plot的函数语法规则&#xff0c;这里不再赘述&#xff0c;可以参考matlab官方文档&#xff0c;https://ww2.mathworks.cn/help/matlab/ref/plot.html#d124e1037051&#xff0c;不看…

GIS开源库GEOS库学习教程(三):空间关系/DE-9IM/谓词

1、DE-9IM 要判断两个多边形的关系&#xff0c;实际上属于几何图形空间关系判断。几何图形并不只有多边形一种&#xff0c;它包括点、线、面构成的任何图形&#xff0c;两两之间相互关系也有很多种&#xff0c;因此空间关系非常复杂。根据前人的研究&#xff0c;总结出了DE-9IM…

图论经典A-Star(A*) Algorithm最短路径,networkx,Python(1)

图论经典A-Star(A*) Algorithm最短路径&#xff0c;networkx&#xff0c;Python&#xff08;1&#xff09; A-Star Algorithm&#xff0c;即为A*&#xff08;A星&#xff09;算法&#xff0c;图的最短路径。 &#xff08;1&#xff09;A-Star(A*)算法需要事先知道起点和终点才…

PhpStorm 2022.3.2消除顶部Windows窗口白色区域

问题图片&#xff1a; 解决方法&#xff1a;勾选Merge main menu with window title 效果图&#xff1a;

第三章:JavaScript 脚本语言(一)

一、简介 JavaScript是web页面中的一种脚本语言&#xff0c;由客户端浏览器解释执行。不需要编译&#xff0c;主要作用是将静态页面转换成用户交互的动态页面。 JavaScript主要有三大部分&#xff1a;ECMAScript (核心)&#xff0c;DOM&#xff08;文档对象模型&#xff09;&…

溯源取证-Linux内存取证 中难度篇

原谅我这么晚才出来文章&#xff0c;因为最近忙着录课&#xff0c;至于为啥没有基础篇&#xff0c;是因为靶场里没看见&#xff0c;哈哈 这个也是研究了好几个晚上才出来的东西&#xff0c;此处场景为linux环境下的rootkit病毒&#xff0c;我们通过这篇文章可以通过内存取证发…

Jmeter测试dubbo服务

1、什么是dubbo接口 Dubbo 接口是阿里巴巴开源的致力于提供高性能和透明化的RPC远程服务调用方案&#xff0c;以及SOA服务治理方案&#xff0c;dubbo框架告别了传统的web service的服务模式&#xff0c;进而改用provider和consumer模式进行服务。为什么是高性能的呢&#xff1f…

制作四个文件启动的镜像

一 环境搭建&#xff1a;vivado2018.3&#xff0c;petalinux2018.3&#xff0c; 1.petalinux环境设置 所使用的编译环境需要使用petalinux这个软件&#xff0c;《第五章Petalinux 的安装》里面的5.1-5.4。有详细的安装过程&#xff0c;按照第五章的顺序把环境搭建好。可以不装…

【PR 基础】新建序列

目录 一、新建序列 二、序列预设 三、设置 一、新建序列 在如下区域点击鼠标右键&#xff0c;选择 新建项目-》序列 或 点击工具栏中的文件-》新建-》序列 二、序列预设 &#xff08;1&#xff09;时基&#xff1a;就是指帧速率&#xff0c;也就是每秒播放帧的数量&#xf…

iOS Matter 操作证书签发方案

在 Matter 配网和操作中&#xff0c;为了信息交互的安全&#xff0c;在配网时&#xff0c;Commissioner自身需要完整的证书&#xff0c;同时需要向设备安装操作证书。 Matter 证书包含&#xff1a; RCA: 根证书 ICA: 中间证书&#xff0c;可选 NOC: 操作证书(注意有以下两种…

人工智能的前沿信息获取之使用文献数据库

人工智能的知识更新迭代非常迅速&#xff0c;因此对人工智能前沿的跟踪非常必要。本文主要介绍了使用文献数据库获取人工智能前沿信息的方法。 文献数据库是检索和下载论文的主要工具&#xff0c;对文献进行检索和下载的技巧在本科公共基础课《文献检索》或《信息检索》等类似…

家庭智能触摸面板开关一Homekit智能

触摸开关&#xff0c;即通过触摸方式控制的墙壁开关&#xff0c;其感官场景如同我们的触屏手机&#xff0c;只需手指轻轻一点即可达到控制电器的目的&#xff0c;随着人们生活品质的提高&#xff0c;触摸开关将逐渐将换代传统机械按键开关。 触摸开关控制原理 触摸开关我们把…

【ESP-IDF】介绍NVS

ESP-IDF是一款由乐鑫科技&#xff08;Espressif Systems&#xff09;开发的面向ESP32和ESP32-S系列芯片的开发框架&#xff0c;NVS&#xff08;Non-Volatile Storage&#xff09;是其中的一项功能。 NVS是一种用于在嵌入式系统中保存持久化数据的键值存储库。在ESP-IDF中&#…

虚拟化技术 — SR-IOV 单根 I/O 虚拟化

目录 文章目录 目录SR-IOVSR-IOV VEBSR-IOV VEPASR-IOV Multi-ChannelSR-IOV OvSSR-IOV 的应用使能 SR-IOV VFs挂在 VF 到 KVM 虚拟机中SR-IOV 的 NUMA 亲和性VF 的网络配置VFs Bonding SR-IOV 虚拟机的热迁移问题 SR-IOV 传统的 I/O 虚拟化方案需要 VMM 来捕获和模拟 VM 的 I…

400左右蓝牙耳机什么牌子音质好?400左右的无线蓝牙耳机推荐

过去几年苹果的AirPods深受大家欢迎&#xff0c;但要论最佳耳机&#xff0c;还要考虑佩戴类型&#xff0c;功能上又分降噪水平&#xff0c;甚至价格上也要实惠&#xff0c;毕竟对于不想太高预算来获得出色音质和舒适度的人来说&#xff0c;这也是他们心中的"最佳"产品…

Kubernetes那点事儿——调度策略

Kubernetes那点事儿——调度策略 前言一、静态Pod二、nodeSelector 节点选择器三、nodeName四、taint污点五、tolerations污点容忍六、容器资源限制七、nodeAffinity节点亲和性 前言 Kubernetes的强大之处离不开它的调度系统&#xff0c;它为Pod调度到某个Node上提供了多种方式…

Linux学习_设备树实现中断

Linux学习_设备树实现中断 中断层级结构设备树_中断控制器设备树_中断子节点驱动程序获取GPIO获取中断号申请中断中断处理函数 中断层级结构 就硬件而言&#xff0c;中断控制器指的就是GIC&#xff0c;但是实际在软件上&#xff0c;图中的GPIO等我们也称之为中断控制器。 外部…

[PyTorch]预训练权重的转换

众所周知&#xff0c;使用大量数据预训练后的骨干网络可以提升整个模型的泛化能力&#xff0c;而我们如果将网络的骨干网络替换后则不能直接使用原来的权重。这个项目的作用是在你替换骨干网络后可以将网络预训练权重一并“偷”过来。 下给结论&#xff1a;将DeeplabV3的骨干网…