我现在必须new一个对象!!!

news2024/11/16 19:28:39

目录

前言

1.new

2.delete

3.底层逻辑

4.定位new

5.对比


前言

🎃之前在使用C语言的时候,我们便使用 malloc 和 calloc 等函数进行动态内存的开辟。但 C++ 之中又引入了两个操作符 new 和 delete 来代替C语言中的函数进行动态内存的管理。下面就一起来学习如何使用吧。

1.new

🎃使用 new 比使用 malloc 方便许多,只需要 new+ 类型即可完成空间申请。而随着后面加的操作不同,能达到不一样的效果。

🎃不仅如此使用 new 之后不需要像 malloc 那样检查是否开辟成功,new 失败会自动抛异常(具体如何,以后再进行讲解)。

int main()
{
	int* p1 = new int;        //申请一个int大小的空间
	int* p2 = new int(3);     //申请一个int大小的空间并初始化成3
	int* p3 = new int[5];     //申请五个int大小的空间
    int* p4 = new int[5]{ 1,2,3,4,5 };  //申请五个int大小的空间并初始化
	return 0;
}

 🎃虽然说 C++ 中同样支持使用C语言的 malloc ,但在有些情况下会显得有些捉襟见肘,比如以下代码:

class A                //定义类A
{
public:
	A(int a = 0, int b = 0)
		:_a(a)
		, _b(b)
	{}
private:
	int _a;
	int _b;
};

int main()
{
	A* p1 = new A(2, 3);   //用new动态开辟
	A* p2 = (A*)malloc(sizeof(A));  //用malloc动态开辟
	if (p2 == NULL)
	{
		perror("malloc");
		return 0;
	}
	return 0;
}

 🎃通过调试我们可以看到,使用 new 开辟出来的空间是已经初始化好的,而使用 malloc 开辟的空间中则是随机值

🎃这是由于 new 对于自定义类型会调用其构造函数进行对象的初始化。若一次申请 个对象的连续,便会调用 次构造函数进行初始化。

2.delete

🎃有开辟就有释放,delete 就是进行释放这个工作。只需要 delete 加空间的首指针便可完成释放,若释放多个对象的空间则需要使用 delete[ ]

int main()
{
	int* p1 = new int;        //申请一个int大小的空间
	int* p2 = new int(3);     //申请一个int大小的空间并初始化成3
	int* p3 = new int[5];     //申请五个int大小的空间
	delete p1;                //正常申请空间则直接delete
	delete p2;
	delete[] p3;              //带[]申请则也需要用delete[]进行释放
	return 0;
}

🎃直接使用 delete[ ] ,没有告诉系统空间多大那系统是如何释放空间的呢?

🎃编译器在 new 的时候,若遇上多组开辟的情形时,会在开辟的空间前额外增加一个位置用于存储开辟空间的大小

🎃根据上文推导,delete 应该会调用类的析构函数进行回收。我们可以使用下面的代码进行验证一下。

class A
{
public:
	A(int a = 7, int b = 8)
		:_a(a)
		, _b(b)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()";
	}
private:
	int _a;
	int _b;
};

int main()
{
	A* p1 = new A();
    delete p1;
	return 0;
}

🎃在当前代码中,只有使用了 delete 才会调用析构函数,而 free 只是单纯的释放空间。若在类之中再次进行动态开辟,而不调用析构函数进行回收时,便会出现内存泄漏

class A
{
public:
	A(int a = 0, int b = 0)
		:_a(a)
		, _b(new int(b))
	{
		cout << "A()" << endl;
	}
	~A()
	{
		delete _b;
		cout << "~A()";
	}
private:
	int _a;
	int* _b;
};

int main()
{
	A* p1 = new A();
	return 0;
}

🎃若在平时的工程之中引发内存泄漏,便会降低代码的运行效率。因此切记,new 和 delete 必须要配合使用。 

3.底层逻辑

🎃通过查看系统文档,我们便能够找到两个全局函数。

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)
    {
        static const std::bad_alloc nomem;
        _RAISE(nomem);
    }
    return (p);
}

void operator delete(void* pUserData)
{
	_CrtMemBlockHeader* pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK); 
	__TRY
		pHead = pHdr(pUserData);
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg(pUserData, pHead->nBlockUse);
	__FINALLY
		_munlock(_HEAP_LOCK);
	__END_TRY_FINALLY
	return;
}

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

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

🎃由上述的底层代码我们发现,operator new 实际也是通过 malloc 来申请空间,如果申请空间成功就直接返回,否则就抛异常。而operator delete 最终是通过 free 来释放空间的

🎃值得注意的是,operator new 和 operator delete 是系统提供的全局函数,并不是运算符重载,只是恰好与其用了相同的名字。

🎃new delete 的本质上就是对 malloc 和 free 的封装。

🎃new 便是先开辟空间再调用构造函数,而 delete 则是先调用析构函数再释放空间

4.定位new

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

class A
{
public:
	A(int a = 0)
		:_a(a)
	{}
	~A()
	{}
private:
	int _a;
};

int main()
{
	A* p = (A*)malloc(sizeof(A));
	p = new(p)A;           //如果构造函数有参数则需要传参2
	return 0;
}

🎃这个操作一般是不会用到的,因为正常情况下我们直接使用 new 就能达到这个结果,没有必要特意 malloc 一次再使用 new 。真正需要使用定位 new 的情况是当我们从内存池中申请空间后,由于这种申请出来的空间是未初始化的,因此需要调用构造函数,所以使用定位new进行初始化。

5.对比

  • malloc free函数new delete 操作符
  • malloc 申请的空间不会初始化,new 可以初始化。
  • malloc 申请空间时,需要手动计算空间大小并传递new 只需在其后跟上空间的类型即可,如果是多个对象,即在[ ]中指定对象个数。
  • malloc 的返回值为 void* , 在使用时必须强转new 不需要。
  • malloc 申请空间失败时,返回的是 NULL ,因此使用时必须判空new 不需要,new 失败则会进行抛异常。
  • 申请自定义类型对象时,malloc/free 只会开辟和清理空间,不会调用构造函数与析构函数,而 new 申请空间后调用构造函数完成对象的初始化, delete 释放空间前调用析构函数完成空间中资源的清理

🎃不要将 new/delete/malloc/free 混在一起使用,否则在特定的情况下便会导致程序崩溃。因此,最好将其区分使用,使用 new 就用 delete 使用 malloc 就用 free 释放。

🎃好了,今天C++内存管理的讲解到这里就结束了,如果这篇文章对你有用的话还请留下你的三连加关注。

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

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

相关文章

苏州源特VPT87DDF01B 隔离变压器 小体积/SMD/3000VDC 隔离

1 产品特点  小体积隔离变压器  隔离电压 3000VDC  工作温度&#xff1a;-40~125℃&#xff08;包含产品温升&#xff09;  存储温度&#xff1a;-55~125℃  SMD 表贴安装  回流焊温度&#xff1a;峰值温度≤250℃&#xff08;10s&#xff09;  回流焊次数&#…

Softing新版HART多路复用器软件支持西门子控制器

用于访问配置和诊断数据的HART多路复用器软件——Softing smartLink SW-HT&#xff0c;现在支持西门子的ET200远程IO和FDT/DTM接口。 smartLink SW-HT是一个基于Docker容器的软件应用。通过该软件&#xff0c;用户可以快速地访问以太网远程IO的HART设备&#xff0c;并且无需额外…

【Linux】进程间通信之管道(pipe)

文章目录前言为什么要进程间通信进程间通信的理论依据管道管道的原理创建匿名管道管道的特点管道的场景利用管道控制子进程命名管道命名管道的打开规则命名管道和匿名管道的区别用命名管道实现server和client通信前言 大家好久不见&#xff0c;今天开始我们将进入进程间通信章…

redis高可用方案:主从复制+哨兵模式,经典案例:一主二从三哨兵,及springboot集成配置

Redis高可用方案&#xff1a;主从复制哨兵模式 经典案例&#xff1a;一主二从三哨兵&#xff0c;及springboot集成配置 第一.配置 1.主节点配置&#xff08;redis.conf&#xff09; # 主节点配置 仅展示必要配置 redis.conf # 保护模式设置为关&#xff0c;方便其他节点访问…

推荐几款炫酷的 MySQL 可视化管理工具!好用到爆!!

MySQL 的管理维护工具非常多&#xff0c;除了系统自带的命令行管理工具之外&#xff0c;还有许多其他的图形化管理工具&#xff0c;工具好用是一方面&#xff0c;个人的使用习惯也很重要&#xff0c;这里介绍 13 款 MySQL 图形化管理工具&#xff0c;供大家参考。 1&#xff1a…

vite .env.test环境使用ant design vue ,打包后a-date-picker控件无法选择日期

前端开发后台管理系统&#xff0c;常用的UI库当属Element UI和 Ant Design Vue&#xff0c;但是前段时间遇到一个奇葩问题&#xff0c;在这里记录一下&#xff0c;防止小伙伴们踩坑。 后台系统&#xff0c;大家肯定都用过时间控件&#xff0c;本期我们使用的是ant design vue&…

2道关于chan的面试题

题目一: 下面关于通道描述正确的是: 1.读nil chan会触发panic 2.写nil chan会触发panic 3.读关闭的chan会触发panic 4.写关闭的chan会触发panic解答&#xff1a;这个提涉及到2个知识点&#xff0c;操作nil的chan会怎么样&#xff0c;操作关闭的chan会怎么样&#xff0c;下面我…

双目相机测距原理

双目相机测距是一种常用的计算机视觉技术&#xff0c;它利用两个摄像头同时拍摄同一场景&#xff0c;通过测量两个摄像头视野中同一物体在图像上的像素差异&#xff0c;从而计算出物体距离的方法。 具体原理如下&#xff1a; 双目相机的构成 双目相机由两个摄像头组成&#…

用ChatGPT怎么赚钱?普通人用这5个方法也能赚到生活费

ChatGPT在互联网火得一塌糊涂&#xff0c;因为它可以帮很多人解决问题。比如&#xff1a;帮编辑人员写文章&#xff0c;还可以替代程序员写代码&#xff0c;帮策划人员写文案策划等等。ChatGPT这么厉害&#xff0c;能否用它来赚钱呢&#xff1f;今天和大家分享用ChatGPT赚钱的5…

Cesium关于3Dtiles的细节分享

介绍 介绍一下Cesium中有关3dTiles的奇淫技巧&#xff0c;存在一些埋坑的地方&#xff0c;以下内容仅为自己摸索的细节和方法&#xff0c;仅供参考&#xff0c;若有更好的办法欢迎讨论 通用快速获取feature中包含的属性信息 有时候需要快速获得3dTiles中的feature中的属性信…

deb文件如何安装到iphone方法分享

Cydia或同类APT管理软件在线安装 Cydia或同类APT管理软件在线安装,这个是最佳的安装方式,因为通常无需考虑依赖关系,但缺点是对网络的要求比较高;命令行中以dpkg-iXXX.deb的形式安装,好处是可以以通配符一次性安装多个deb,而且也可以直接看到脚本的运行状况和安装成功/失…

执行命令行程序测试自动化

这几天有一个小工具需要做测试&#xff0c;是一个命令行工具&#xff0c;这个命令行工具有点类似mdbg等命令行工具&#xff0c;即程序运行后&#xff0c;在命令行等待用户敲入的命令&#xff0c;处理命令并显示结果&#xff0c;再继续等待用户敲入新的命令。 原来的测试用例都…

Vue实现自动化平台(五)--用例编辑页面

上一章&#xff1a;Vue实现自动化平台&#xff08;四&#xff09;--接口管理页面的实现_做测试的喵酱的博客-CSDN博客 github地址&#xff1a;https://github.com/18713341733/vuemiaotest 这个目前只是用来练手的&#xff0c;项目还没成型。等以后我写完了&#xff0c;再更…

公网远程访问局域网SQL Server数据库【无公网IP内网穿透】

目录 1.前言 2.本地安装和设置SQL Server 2.1 SQL Server下载 2.2 SQL Server本地连接测试 2.3 Cpolar内网穿透的下载和安装 2.3 Cpolar内网穿透的注册 3.本地网页发布 3.1 Cpolar云端设置 3.2 Cpolar本地设置 4.公网访问测试 5.结语 转发自CSDN远程穿透的文章&…

不用但一定要懂 ---- iOS 之 响应链、传递链 与 手势识别

iOS 事件的主要由&#xff1a;响应连 和 传递链 构成。一般事件先通过传递链&#xff0c;传递下去。响应链&#xff0c;如果上层不能响应&#xff0c;那么一层一层通过响应链找到能响应的UIResponse。 响应链&#xff1a;由最基础的view向系统传递&#xff0c;first view ->…

c/c++:原码,反码,补码和常见的数据类型取值范围,溢出

c/c&#xff1a;原码&#xff0c;反码&#xff0c;补码和常见的数据类型取值范围&#xff0c;溢出 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0c; 我所知道的周边的会c的同学&#xff0c;可手握…

前脚我的 GPT4 被封,后脚收到了文心一言的邀请账号

大家好&#xff0c;我是二哥呀。 一早醒来&#xff0c;我的 ChatGPT Plus 账号就惨遭封禁&#xff0c;很不幸&#xff0c;我刚冲的 Plus 会员&#xff0c;用了不到一周的时间&#xff08;&#x1f62d;&#xff09;。 我没用亚洲的IP&#xff0c;所以网上传的那些不使用亚洲IP…

vuex中的 mapState, mapMutations

vuex中的 mapState&#xff0c; mapMutations Start 今天使用vuex的过程中&#xff0c;遇到 mapState&#xff0c; mapMutations 这么两个函数&#xff0c;今天学习一下这两个函数。 本文介绍的vuex基于 vuex3.0 1. 官方文档说明 1.1 mapState 官方解释 点击这里&#xff1…

深入理解IP地址

我们在浏览器中直接输入IP地址就可以访问某一个神秘的网站&#xff0c;那么这个IP地址是如何划分的呢&#xff1f; IP&#xff0c;英文全写为Internet Protocol&#xff0c;指TCP/IP网络体系中的网际互联协议&#xff0c;工作在OSI模型的网络层(简单了解即可)。 更多内容欢迎访…

数据分析之Matplotilb数据可视化

文章目录1.Matplotilb 基础plt.show()函数plt.plot()函数基本用法例子坐标轴显示的范围传入Numpy数组传入多组数据线条属性使用plt.plot()的返回值来设置线条属性plt.setp()修改线条性质子图plt. subplot (numrows, numcols,fignum)形式3.电影数据绘图(1)绘制每个国家或地区的电…