当前位置: 首页 > ds >正文

C++ --- new与delete

new与delete

  • 一、回顾
    • 1.malloc
    • 2.calloc
    • 3.realloc
    • 4.free
  • 二、new与delete的特殊之处
      • (1)
      • (2)
  • 三、new与delete的底层原理
  • 四、总结

一、回顾

在C语言阶段我们学习了动态内存管理:malloc,calloc,realloc,free。

1.malloc

malloc — 向堆上申请一块空间,其空间大小由我们自己定义大小,申请成功返回此连续空间的起始地址,否则返回空指针。

	//使用malloc创建一个10个空间大小的整型数组。int* ptr1 = (int*)malloc(sizeof(int) * 10);

调试观察:
在这里插入图片描述
如上图,动态申请了一个10个空间大小的整型数组。

2.calloc

calloc — 在malloc的基础上多了一个初始化的作用,会将所指向空间元素初始化成0。

	//使用calloc创建一个10个空间大小的整型数组。int* ptr2 = (int*)calloc(10, sizeof(int));

调试观察:
在这里插入图片描述
对比malloc申请出来的空间,多进行了一步初始化成0的操作。

3.realloc

realloc — 用法是扩容,跟上面两个不同,有两种情况。
(1)原地扩容,若要扩容的空间之后紧挨着的空间允许扩容操作,此就是原地扩容
(2)异地扩容,若要扩容的空间之后紧挨着的空间不支持扩容操作,则会在堆上重新找一块大小相等的空间,将原空间内的数据拷贝进新空间,再将旧空间释放,返回新空间的起始地址。
图解如下:
在这里插入图片描述

4.free

free的作用是将我们动态申请的空间不用了之后释放掉。
将上述两个动态开辟的空间给释放掉:

	free(ptr1);ptr1 = nullptr;   free(ptr2);ptr2 = nullptr;

秉承写代码优良作风,一般free之后将其指针变量置为空,以防出现野指针。

但由于C++引入了类这种自定义类型,上述三种普遍针对内置类型的动态开辟空间的方法就不再适用了,所以C++语言新引入了动态开辟空间的方法:new,delete。

二、new与delete的特殊之处

new和delete是一对关键字,作用就是动态开辟空间和释放空间。

第一个场景:内置类型和自定义类型的对象创建场景。
对于内置类型示例代码如下:

	//1、使用new创建一个整型变量int* ptr1 = new int;         // --- 没有初始化int* ptr2 = new int(1);      // --- 初始化操作//2、使用new创建一个10个空间大小的整型数组int* ptr3 = new int[10];                     // --- 没有初始化int* ptr4 = new int[10] {1, 2, 3, 4, 5};     // --- 初始化操作//同样不要忘记手动释放内存空间delete ptr1;      //普通变量释放内存空间delete ptr2;delete[] ptr3;    //数组释放内存空间需要加上[]delete[] ptr4;

对于自定义类型示例代码如下:

class A
{
public:A(){cout << "调用无参构造函数!!!" << endl;}A(int year, int month, int day):_year(year),_month(month),_day(day){cout << "调用有参构造函数!!!" << endl;}~A(){cout << "调用析构函数!!!" << endl;}private:int _year = 2000;int _month = 1;int _day = 1;
};//3、使用new创建一个类类型的对象A* a1 = new A();A* a2 = new A(2025, 5, 13);//同样不要忘记手动释放内存空间

运行结果:
在这里插入图片描述

上图运行结果就是new与delete的特别之处:

(1)

new会先去堆上动态开辟空间,再调用构造函数。
delete会先调用析构函数,再释放内存空间。

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

另一个场景,即malloc,new申请失败的场景。

对于malloc申请失败示例代码如下:

	//1.malloc申请失败的场景int* ptr1;for (int i = 0; i < 1000; i++){ptr1 = (int*)malloc(sizeof(int) * 1024 * 1024);  //1024 = 2^10,此处为4M大小if (ptr1){cout << i << "->" << ptr1 << endl;}else{break;}}

运行结果:
在这里插入图片描述
malloc申请失败后返回的为0(检查返回值是否为NULL),代表程序正常结束。

对于new申请失败示例代码如下:

	//2.new申请失败的场景int* ptr2;for (int i = 0; i < 1000; i++){ptr2 = new int[1024 * 1024];cout << i << "->" << ptr2++ << endl;}

运行结构:
在这里插入图片描述
new申请失败返回为3,不为0,说明其返回机理和malloc不同,程序非正常结束。

(2)

new的申请失败机理是抛异常,这点与malloc的申请失败截然不同。

下面演示一点如何处理异常(了解即可,后续会详细讲解):
上述new的代码是在一个全局函数Test_3里面,所以直接对Test_3进行异常处理。

int main()
{//Test_1();//Test_2();try{Test_3();}catch(const exception& e){cout << e.what() << endl;}return 0;
}

运行结果:
在这里插入图片描述
处理异常后程序返回0,正常结束,并且打印了一句"bad allocation",这句话意思就是空间分配异常。

三、new与delete的底层原理

new与delete的底层原理其实就是重载的两个全局函数,operator new 与 operator delete,这两个在其主要作用。

对于operator new:
在这里插入图片描述
观察会发现一个熟悉的身影malloc,所以别看new听起来高大上,它的底层开辟内存空间的实现依旧是使用的malloc,如此这般麻烦操作就是为了将new改变成抛出异常,所以刚刚抛出异常的那一句话就是从这里出来的。
同理operator delete的释放内存空间的实现使用的就是free。

汇编层验证(基于对自定义类型):
在这里插入图片描述
在这里插入图片描述
new的功能先调用operator new这个全局函数来开辟内存空间,再去调用构造函数。
delete的功能先调用析构函数清理资源,再调用operator delete这个全局函数来释放内存空间。

其实还有一组全局函数operator new[ ]和operator delete[ ],此全局函数就是对于N个对象空间的申请与释放。
(1)operator new[ ]:在operator new[]中实际调用operator new函数完成N个对象空间的申请,并且在申请的空间上执行N次构造函数。
(2)operator delete[ ]:在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间。

四、总结

(1)对于内置类型:
new与malloc这写动态开辟空间的函数功能上没有区别,只是malloc申请失败会返回NULL,而new会抛出异常。

(2)对于自定义类型:
malloc这样的函数就无法使用了,而new的本质是先调用operator new这个全局函数来开辟内存空间,再去调用构造函数;delete的本质是先调用析构函数清理资源,再调用operator delete这个全局函数来释放内存空间。

(3)不同的动态开辟内存空间要配套使用,也就是使用malloc开辟空间,则使用free释放空间;使用new开辟空间,则使用delete释放空间;使用new开辟了一块连续的数组空间,则使用delete[ ]释放空间,一定不要乱配对和错误使用。

http://www.xdnf.cn/news/6679.html

相关文章:

  • upload-labs通关笔记-第8关 文件上传之点绕过
  • visio下载安装教程超详细图文教程(附完整安装包)|visio2024
  • 《解锁数字藏品交易系统的底层密码:区块链架构抉择》
  • HNUST湖南科技大学-安卓Android期中复习
  • WebRTC中的几个Channel
  • 【串流VR手势】Pico 4 Ultra Enterprise 在 SteamVR 企业串流中无法识别手势的问题排查与解决过程(Pico4UE串流手势问题)
  • uni-app 中适配 App 平台
  • UML活动图零基础入门:1 分钟掌握核心逻辑(附实战模板)
  • k8s部署grafana
  • Ai Agent革命:不是流程驱动,而是模型为魂
  • Perl语言深度考查:从文本处理到正则表达式的全面掌握
  • 地下停车场调频广播无线覆盖系统:融合精准选频光纤传输均匀覆盖于一体的创新型地下车库广播无线覆盖平台
  • 【数据开发】埋点体系的讲解 - 埋点方式、原理、优缺点
  • C#里使用Prism.Core的例子
  • 技术剖析|线性代数之特征值分解,支撑AI算法的数学原理
  • 掌握 LangChain 文档处理核心:Document Loaders 与 Text Splitters 全解析
  • 我设计的一个安全的 web 系统用户密码管理流程
  • GpuGeek 实操指南:So-VITS-SVC 语音合成与 Stable Diffusion 文生图双模型搭建,融合即梦 AI 的深度实践
  • 以项目的方式学QT开发C++(二)——超详细讲解(120000多字详细讲解,涵盖qt大量知识)逐步更新!
  • 层序遍历(BFS)核心逻辑:从二叉树到复杂题型的一通百通
  • 【电子通识】热敏纸的静态发色性能和动态发色性能测试方法
  • 小结: js 在浏览器执行原理
  • JavaScript数据类型转换
  • [250515] 腾讯推出 AI 编程助手 CodeBuddy,对标 Cursor
  • 本地部署 私有云网盘 Nextcloud 并实现外部访问
  • KiCad 获取立创商城上面的元器件符号、封装和3D模型
  • 登录接口的密码进行RSA加密Java脚本
  • Apollo学习——planning模块(3)之planning_base
  • Linux/Centos7离线安装并配置MySQL 5.7
  • 龙虎榜——20250515