C++ operator new和operator delete的深入讲解

news2024/10/17 5:02:51

 个人主页:Jason_from_China-CSDN博客

所属栏目:C++系统性学习_Jason_from_China的博客-CSDN博客

所属栏目:C++知识点的补充_Jason_from_China的博客-CSDN博客

前言

关于operator new和operator delete我们需要明确一个概念,这两个都是一个函数,和malloc,free一样都是一个函数,但是这里需要明确的是,这里只是类似,不是一样。

operator new语法结构

语法结构

#include<iostream>
int main()
{
	//标准的分配内存的空间形式
	//分配一个内置类型,int内置类型的空间
	void* ptr1 = operator new(sizeof(int));
	//分配一个数组形式的内存空间
	void* ptr4 = operator new[](10 * sizeof(int));

	//这样的形式也是可以使用的,但是可能会出现问题,因为operator new是一个没有初始化,也就是未定义的内存空间
	//这样分配内存容易导致错误访问,所以还是建议使用标准化来分配内存空间
	//void* ptr2 = operator new(10 * sizeof(int));
	//void* ptr3 = operator new[](sizeof(int));
	//void* ptr4 = operator new[](10 * sizeof(int));

	return 0;
}

operator delete语法结构

#include<iostream>
int main()
{
	//标准的分配内存的空间形式
	//分配一个内置类型,int内置类型的空间
	void* ptr1 = operator new(sizeof(int));
	//分配一个数组形式的内存空间
	void* ptr4 = operator new[](10 * sizeof(int));

	//这样的形式也是可以使用的,但是可能会出现问题,因为operator new是一个没有初始化,也就是未定义的内存空间
	//这样分配内存容易导致错误访问,所以还是建议使用标准化来分配内存空间
	//void* ptr2 = operator new(10 * sizeof(int));
	//void* ptr3 = operator new[](sizeof(int));
	//void* ptr4 = operator new[](10 * sizeof(int));

	//operator new和delete这里是函数,所欲我们销毁的时候是函数的形式销毁,销毁的语法结构
	//释放单个内存空间
	

	//释放内存空间、标准化释放内存空间
	operator delete(ptr1);
	operator delete[](ptr4);


	return 0;
}

operator new+operator delete原理讲解

关于operator new

  • operator new我们可以看出来,其实new是operator new的一个封装,因为new在使用的时候会调用operator new
  • operator new的底层实现上面是调用malloc来实现开辟空间的


 

关于operator delete

  • 从operator delete我们可以看出来,delect本质也是对operator delete函数的封装,再严谨的讲解就是,是对free的封装,free是对free_dbg(p,_NORMAL_BLOCK)的封装
  • 所以我们可以更清晰的看出,operator delete是一个函数,不是关键字
  • delete是关键字,不是函数

operator new+operator delete和new+delete的深入对比

一、内置类型

  1. 对于内置类型,new 和 malloc、delete 和 free 基本类似。不同在于:new/delete 申请和释放单个元素空间,new []/delete [] 申请和释放连续空间;new 申请空间失败会抛异常,malloc 失败返回 NULL。
  2. 抛异常(就是告诉你哪里有错,并且继续运行程序)

二、自定义类型 new 的原理

  1. 调用 operator new 函数申请空间,底层类似 malloc(malloc 不抛异常)。
  2. 在申请的空间上执行构造函数完成对象构造。

三、自定义类型 delete 的原理

  1. 在空间上执行析构函数清理对象资源,本质类似 free 的调用。
  2. 调用 operator delete 函数释放对象空间。

四、new T [N] 的原理

  1. 调用 operator new [] 函数实际在其中调用 operator new 完成 N 个对象空间申请。
  2. 在申请的空间上执行 N 次构造函数。

五、delete [] 的原理

 
  1. 在释放的对象空间上执行 N 次析构函数,清理 N 个对象资源。
  2. 调用 operator delete [] 释放空间,实际在其中调用 operator delete。

operator new+operator delete和new+delete使用时候的注意事项

不要交错使用,很容易导致资源使用出现问题

  • operator new只是开辟空间,不会进行初始化的
  • operator delete是只是销毁空间,不会清理资源的
  • new,在开辟空间的时候会初始化并且构建资源
  • delete,销毁空间的时候会调用构造函数销毁资源
  • 知道,尽量不要交错使用就可以
#include<iostream>
using namespace std;

class A
{
public:
	A(int capacity = 4, int size = 0)
		:_Capacity(capacity)
		, _size(size)
		, _arr(nullptr)
	{
		//创建空间
		_arr = new int[_Capacity];
		printf("A()");
	}
	~A() 
	{
		//这里释放我们是需要匹配方括号,这里是释放数组形式的内容,自适应找到需要释放的内存
		delete[] _arr;
		_Capacity = 4;
		_size = 0;
		printf("~A()");

	}

private:
	int* _arr;
	int _Capacity;
	int _size;
};




//operator new创建空间,new构造
//我们需要使用 operator delete先销毁空间,再使用delete销毁资源
//并且是不能直接使用delete来进行销毁空间的,因为我们创建的空间是未定义的,new构造之后我们是会申请资源甚至空间的
//如果直接用delect销毁不使用operator delete销毁就会导致空间没有销毁
//如果只是使用operator delete销毁空间,就会导致资源没有销毁
//并且此时还应该先试用delete来销毁资源 再销毁空间
int main()
{
	A* p = new A[10];
	delete[] p;
	printf("\n");
	void* ptr1 = operator new[](10 * sizeof(A));
	//初始化,我们也可以进行定位new进行初始化,定位new里面我们会进行讲解
	for (int i = 0; i < 10; ++i) {
		new (static_cast<A*>(ptr1) + i) A(i * 10);
	}

	// 使用这些 A 对象

	// 销毁这些对象
	for (int i = 0; i < 10; ++i) {
		(static_cast<A*>(ptr1) + i)->~A();
	}
	operator delete[](ptr1);


	return 0;
}

  • operator new创建空间,new构造
  • 我们需要使用 operator delete先销毁空间,再使用delete销毁资源并且是不能直接使用delete来进行销毁空间的,因为我们创建的空间是未定义的,new构造之后我们是会申请资源甚至空间的
  • 如果直接用delect销毁不使用operator delete销毁就会导致空间没有销毁
  • 如果只是使用operator delete销毁空间,就会导致资源没有销毁
  • 并且此时还应该先使用delete来销毁资源 再使用operator delete销毁空间

定位new表达式(placement-new) (了解)

定位new主要使用的区域在于内存池,所以这里作为了解进行学习

一、在特定内存位置构造对象

  1. 可以在预先分配好的内存区域中创建对象,而不依赖于默认的内存分配机制。例如,使用operator new或其他方式分配了一块内存后,可以使用定位new在这块内存上构造对象。
  2. 语法形式为:new (pointer) Type(args...),其中pointer是指向已分配内存的指针,Type是要构造的对象类型,args...是构造函数的参数。
  3. 当使用普通的newdelete操作符时,delete会自动调用对象的析构函数并释放内存。但是对于通过定位new创建的对象,由于没有通过常规的内存分配机制,仅仅使用delete或者operator delete来释放内存不会自动调用析构函数。
  4. 此时我们发现可以用operator new开辟空间,new构造没有那么麻烦了,我们可以直接定位,可以直接看下面代码,但是这里有问题的就是不支持显示构造,但是支持显示析构

#include<iostream>
using namespace std;
class A
{
public:
	A(int capacity = 4, int size = 0)
		:_Capacity(capacity)
		, _size(size)
		, _arr(nullptr)
	{
		//创建空间
		_arr = new int[_Capacity];
		printf("A()");
	}
	~A() 
	{
		//这里释放我们是需要匹配方括号,这里是释放数组形式的内容,自适应找到需要释放的内存
		delete[] _arr;
		_Capacity = 4;
		_size = 0;
		printf("~A()");

	}

private:
	int* _arr;
	int _Capacity;
	int _size;
};

int main()
{
	//正常函数的调用
	A* p = new A[10];
	delete[] p;
	printf("\n");

	//定位的使用,operator new创建一个空间,new定位进行构造
	void* ptr1 = operator new[](10 * sizeof(A));
	new(ptr1) A[10];//定位不支持显示构造,必须有默认构造

	//delete[] ptr1;//定位是需要显示调用析构函数来进行释放资源的。直接使用delect自动释放资源是不能实现的
	for (int i = 0; i < 10; i++)
	{
		//static_cast强制类型转化关键字//<A*>转化为A类型//(ptr1) + i)->~A();循环显示调用析构函数
		(static_cast<A*>(ptr1) + i)->~A();
	}

	operator delete[](ptr1);



	return 0;
}

二、与内存池等技术结合使用

  1. 在一些高性能场景下,为了避免频繁的内存分配和释放开销,可以使用内存池预先分配一大块内存,然后在需要创建对象时使用定位new在内存池中选取合适的位置构造对象。
  2. 这样可以提高内存分配的效率,减少内存碎片的产生。

三、资源管理和对象生命周期控制

  1. 通过定位new,可以更精细地控制对象的构造和析构时机,特别是在一些复杂的资源管理场景中。
  2. 例如,可以在特定的资源初始化后,在与之相关的内存位置构造对象,确保资源和对象的生命周期紧密关联。

四、注意事项

  1. 使用定位new构造的对象,在销毁时需要手动调用析构函数,而不能直接使用delete来释放内存,因为delete会尝试释放由默认内存分配机制分配的内存,而不是定位new所使用的内存。
  2. 例如:new (ptr) Type(args...);构造的对象,在销毁时应该使用ptr->~Type();来调用析构函数。

malloc/free 和 new/delete 的区别

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

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

相关文章

2024全新UI网址发布页源码带黑夜模式

源码简介 2024全新UI网址发布页源码带黑夜模式&#xff0c;带网站延迟测速&#xff0c;该源码是html源码&#xff0c;可以做个引导页面。 安装教程 纯HTML&#xff0c;直接将压缩包上传网站目录解压即可(或在本地直接打开) 首页截图 源码下载 2024全新UI网址发布页源码带黑…

​​Vision Pro/空间计算小白体系化练手案例:从入门到精通的实战项目指南

引言 随着苹果Vision Pro的发布,空间计算技术正迎来前所未有的发展机遇。对于希望进入这一领域的开发者来说,掌握visionOS及相关工具链是至关重要的第一步。本文将介绍一系列由浅入深的实战项目,旨在帮助初学者系统地学习并实践visionOS开发。这些项目不仅适合个人学习,也…

踩坑日记:线上接口超时问题排查

1.背景: 上线后,功能测试. 进入小程序页面发现很慢,耗时超过5秒,打开skywalking发现大量接口耗时都很高. 2.top命令 服务器top命令查看cpu资源发现占用并不高 3.mysql查看sql运行情况 # 当前运行的所有事务 select * from information_schema.innodb_trx; 1 | …

国内液压一体式潜孔钻机市场相对分散

根据研究团队调研统计&#xff0c;2023年全球液压一体式潜孔钻机市场销售额达到了52亿元&#xff0c;预计2030年将达到90亿元&#xff0c;年复合增长率&#xff08;CAGR&#xff09;为7.1%&#xff08;2024-2030&#xff09;。中国市场在过去几年变化较快&#xff0c;2023年市场…

计算机网络基础(1)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络基础 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 计算机网…

100. UE5 GAS RPG 显示范围魔法的攻击范围

在这一篇里&#xff0c;我们将制作一个范围魔法&#xff0c;释放魔法时&#xff0c;我们将在鼠标拾取位置绘制一个魔法光圈&#xff0c;用于显示技能释放时攻击的范围&#xff0c;然后再次点击可以释放技能。 创建贴花类 魔法范围标识的光圈&#xff0c;我们采用贴花实现&…

AI 代码工具大揭秘:提高编程效率的必备神器!

近年来&#xff0c;人工智能得到了迅猛的发展&#xff0c;并在各行各业都得到了广泛应用。尤其是近两年来&#xff0c;AI开发工具逐渐成为开发者们的新宠&#xff0c;其中GitHub Copilot更是引发了无限可能性的探索。在本文中&#xff0c;我将向大家介绍一些实用性较高的智能开…

徒步1 -经典贪心

# 问题描述 小明想从A徒步到B&#xff0c;总路程需要M天&#xff0c;路程中为了确保安全&#xff0c;小明每天需要消耗1份食物。 在起点及路程当中&#xff0c;零星分布着N个补给站&#xff0c;可以补充食物&#xff0c;不同补给站的食物价格可能不同。 请问小明若要安全完…

求双十一宠物空气净化器推荐!希喂、范罗士、有哈哪款好用?

不知道大家有没有觉得&#xff0c;今年的双十一比以往要冷清些。还是朋友提醒我才知道&#xff0c;预售已经开始几天了&#xff0c;真切的体会到了消费降级带来的变化。不过自己的东西可买可不买&#xff0c;猫主子的口粮和生活用品还是要保证的。 把小猫接回来已经一年了&…

HTTP服务

一.http协议的介绍 http应用层协议 超文本传输协议&#xff08;比如网站上面的超链接&#xff09; 作用&#xff1a;构建网站服务器&#xff0c;可以在客户端与网站服务器之间传输文本数据。 浏览器会将文本数据解析成对应的图片&#xff0c;视频进行展示。 1.网站类型 静…

字符串(4)_字符串相乘_高精度乘法

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 字符串(4)_字符串相乘_高精度乘法 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…

AD9361 的 TX 输出中添加前置放大器,并在 RX 输入中添加 LNA。

AD9361 的 TX 输出中添加前置放大器&#xff0c;并在 RX 输入中添加 LNA。 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/AD-TRXBOOST1-EBZ.html https://wiki.analog.com/resources/eval/user-guides/ad-trxboost1-ebz/in…

区块链技术与农产品溯源:实现透明供应链的关键

引言 随着食品安全问题和消费者对产品质量要求的提升&#xff0c;农产品溯源变得越来越重要。消费者希望知道他们购买的农产品从何而来&#xff0c;经历了哪些过程以及是否符合安全标准。区块链技术因其去中心化、不可篡改和透明的特点&#xff0c;成为实现农产品溯源的理想选…

程序员如何使用AI工具进行设计开发?

一、需求分析阶段 自然语言处理辅助理解需求&#xff1a; 使用自然语言处理工具&#xff0c;如 ChatGPT 等&#xff0c;将复杂的业务需求描述转化为更清晰的技术要求。例如&#xff0c;向 AI 解释项目的背景和目标&#xff0c;让它帮助梳理关键需求点和可能的技术挑战。通过与…

集合框架10:泛型接口、泛型方法

视频链接&#xff1a;13.20 泛型方法_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1zD4y1Q7Fw?spm_id_from333.788.videopod.episodes&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5&p20 1. 泛型接口 创建一个泛型接口&#xff1a; package com.yundait.Demo…

【C语言】数据输出格式控制

数据的输出格式修饰 常用两种&#xff1a; 整型中&#xff0c;输出数据左对齐、右对齐、占m位、不足m位前补0。浮点型中&#xff0c;默认通过四舍五入保留小数点后6位&#xff0c;通过参数设置保留小数点后n位。 #include <stdio.h> #define PI 3.14159 /* 功能&#x…

sim卡文件系统

### 5.2 初始通信建立程序 初始通信建立程序应遵循3GPP TS 31.101 [55]的规定&#xff0c;但有以下限制&#xff1a; - 对于3V及以下的SIM卡&#xff0c;最大时钟频率为4MHz&#xff0c;因此必须遵守3GPP TS 31.101 [55]中规定的相应功耗限制。 - ATR内容&#xff1a;如果SIM在…

如何使用 pnpm 进行打补丁patch操作?推荐两个方法

前言 作为一个前端开发者&#xff0c;我们每天都在和各种各样的库和依赖打交道。node_modules 目录中存放着我们项目的各种依赖。我们有时需要对其中的一些依赖进行修改&#xff0c;比如修复某个 bug 或者增加某些自定义功能。这时候&#xff0c;给 node_modules 打补丁就显得…

极速fastpdf软件卸载后还是显示在pdf可用软件里,解决办法

如下图&#xff0c;我已经卸载了fastpdf并且电脑文件夹里没有该路径。但是打开pdf时&#xff0c;在可用软件选项里还是存在这个路径。原因是虽然把软件卸载了&#xff0c;但是注册表没有删除干净 解决办法&#xff1a; WinR输入regedit进入注册表编辑器&#xff0c;然后CtrlF搜…

裸硅芯片无压烧结银,助力客户降本增效

裸硅芯片无压烧结银&#xff0c;助力客户降本增效 作为全球烧结银的领航者&#xff0c;善仁新材重“芯“出发&#xff0c;再次开发出引领烧结银行业的革命----推出裸硅芯片的无压烧结银AS9332&#xff0c;此款烧结银得到客户的广泛认可。 在半导体技术的飞速发展中&#xff0…