C++:深入理解operator new/operator delete

news2024/11/24 16:59:53

动态内存管理

  • 1.语法层面
    • 1.基本语法
      • 注意点
  • 2.new/delete和malloc/free的区别
  • 3.operator new和operator delete函数(底层重点)
    • 1.operator new/delete原理
    • 2.图解
      • 1.new/new[]
      • 2.delete/delete[]
    • 3.new[n]和delete[]
  • 4.定位new
    • 1.定义
    • 2.使用格式

1.语法层面

1.基本语法

class Node
{
public:
	Node(int val)
		:_val(val),_next(nullptr)
	{
	}
private:
	int _val;
	Node* _next;
};

void test()
{
	int* p1 = new int;                 //申请空间
	int* p2 = new int(1);              //申请空间 + 初始化
	int* p3 = new int[4];              //申请4个int整型空间
	int* p4 = new int[4] {1, 2, 3, 4}; //申请4个整型空间 + 初始化
	Node* n1 = new Node(2);            //申请空间 + 调用构造函数
	delete p1;
	delete p2;
	delete[] p3;
	delete[] p4;
	delete[] n1;
}

在这里插入图片描述

注意点

1.申请单个空间时使用new/delete,申请一段连续空间时使用new[ ]/delete[ ],且一定要匹配使用
2.对于自定义类型,new会调用构造函数,delete会调用其的析构函数

2.new/delete和malloc/free的区别

用法上:

(1)new/delete可以自定义初始化,而malloc/free只负责开空间,不会初始化,且用法上比malloc/free方便

(2)new/delete不需要手动计算申请空间的大小,直接在后面加上类型即可

(3)new/delete不需要强转,malloc和free由于返回值类型为void*,因此需要强转使用

(4)new/delete在实现时使用了抛异常的机制,可以更好的处理问题,而malloc/free则需要手动实现判断

(5)new/delete可以更好的处理自定义类型,对于自定义类型,new的时候调用它的构造函数,delete的时候调用它的析构函数,同时new的时候还可以通过隐式类型转换调用它的有参构造,这对于链表的构造非常方便

(6)new/delete是操作符,malloc和free是函数

3.operator new和operator delete函数(底层重点)

1.operator new/delete原理

在这里插入图片描述

2.图解

1.new/new[]

new/new[]的调用规则如下图。

在这里插入图片描述

2.delete/delete[]

delete/delete[]的调用规则如下图。

在这里插入图片描述

new/delete操作符在二进制指令上本质是调用operator new和operator delete函数,而operator new在底层是对malloc的封装(operator delete)类似。

注意:delete和delete[]必须先调用析构函数,否则对于栈这样的类,它们申请的空间无法释放

在这里插入图片描述

3.new[n]和delete[]

在使用new[n]时,编译器可以通过n确定调用多少次构造函数,但是delete[]时我们并不会给值,那么调用delete[]时编译器如何知道调用多少次析构函数呢。

先看如下代码。

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

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

int main()
{
	A* a = new A[10];
	delete[] a;
	return 0;
}

按照计算,每一个A中有一个_a,为4个字节,那么申请10个A应该为40字节,可是我们观察汇编,却发现申请了48字节(30为16进制表示),那么多余的8个字节是干什么的呢?

在这里插入图片描述

以下为a的地址,通过内存窗口我们可以看到确实开出了10个整型的空间。

在这里插入图片描述

但是如果再向上看一点,就会发现我们多开出的8个字节。其中存储了十六进制的a(即十进制的10),即为我们需要调用构造函数和析构函数的次数。
在这里插入图片描述

总结:

在我们调用new[]时,会有一个接收的地址,这个地址是我们开辟好的空间的第一个位置的地址,但是编译器其实在这个位置之前多开了字节来存储对象的个数,这样在调用delete[]时就可以通过这个值知道调用多少次析构函数了。如果使用delete[] 来释放空间,那么其在内部会从a指向的空间再向前移动的位置开始释放空间,而不是从a处直接释放空间,如果从a处直接释放空间则会报错。

那么如果不匹配使用,比如:

在这里插入图片描述

此时,由于调用的delete,因此它不会进行指针向前移动字节,而是直接从a的位置开始释放,而申请的空间不能分割释放(也就是释放位置错了),因此会报错。

在这里插入图片描述

上述情况是在我们显式写了析构函数的情况下,==如果我们没有显式写析构函数,那么由编译器默认生成的析构函数没有作用,因此编译器会优化掉,不会调用析构函数,也不会去存储调用次数,不会多申请那一部分空间,==因此不会报错。

从下图可以看到没有多申请空间来存储个数。

在这里插入图片描述

注意:

​ 新版编译器会给出警告如图:

在这里插入图片描述

4.定位new

1.定义

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

可以理解为这块空间我先拿到它的使用权,但是我先不初始化使用,等到需要使用的时候再调用定位new。

2.使用格式

new (place_address) type或者new (place_address) type(initializer-list)

注:place_address必须是一个指针,initializer-list是类型的初始化列表

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

nitializer-list是类型的初始化列表

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

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

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

相关文章

EPSON晶振应用到汽车电子产品上的型号有哪些?

EPSON品牌应用在汽车电子产品上的晶振.&#xff0c;当然也少不了晶振可能最熟悉的就是32.768K系列和26MHZGPS晶振用的多。 在汽车里每一个部件都应有的不一样,甚至多次使用到同一尺寸,不同频率的晶振.爱普生品牌晶振型号就有几百种,很容易混淆,要想记住汽车里所应用到的不是件…

python爬虫(Selenium案列)第二十四

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

windows docker desktop==spark环境搭建

编写文件docker-compose.yml version: 3services:spark-master:image: bde2020/spark-master:3.1.1-hadoop3.2container_name: spark-masterports:- "8080:8080"- "7077:7077"- "2220:22"volumes:- F:\spark-data\m1:/dataenvironment:- INIT_D…

HiveSql中的函数家族(二)

一、窗口函数 1、什么是窗口函数 在 SQL 中&#xff0c;窗口函数&#xff08;Window Functions&#xff09;是一种特殊的函数&#xff0c;它允许在查询结果集的特定窗口&#xff08;通常是一组行&#xff09;上执行聚合、分析和计算操作&#xff0c;而无需聚合整个结果集。窗口…

Linux 2.进程(守护进程)

守护进程 何谓守护进程常见守护进程进程查看命令pskill命令编写简单守护进程守护进程的父进程 何谓守护进程 daemon&#xff0c;表示守护进程&#xff0c;简称为d&#xff08;进程名后面带d的基本就是守护进程&#xff09; 长期运行&#xff08;一般是开机运行直到关机时关闭&…

Flask项目在Pycharm中设置局域网访问

打开PyCharm导入本应用。点击Run标签中的Edit Configurations 其中Target type选择Script path&#xff0c;Target填入本项目中app.py的路径&#xff0c;Additional optional填入--host0.0.0.0(不要有空格)。 再重新运行项目&#xff0c;会观察到除了原本的http://127.0.0.1:50…

java在线问卷调查系统的设计与实现(springboot+mysql源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的在线问卷调查系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于java的在线问卷调查…

函数 基础知识

本笔记为观看 50 函数-函数的定义_哔哩哔哩_bilibili的学习笔记 1 函数概述 作用:将一段经常使用的代码封装起来&#xff0c;减少重复代码一个较大的程序&#xff0c;一般分为若干个程序块&#xff0c;每个块实现特定的功能。 2 函数的定义 eg: int max(int a,int b); {retu…

社交媒体数据恢复:钉钉

在数字化办公日益普及的今天&#xff0c;钉钉作为一款综合性的企业级通讯工具&#xff0c;已经深入到众多企业和个人的工作与生活中。然而&#xff0c;在日常使用过程中&#xff0c;我们难免会遇到一些意外情况导致数据丢失的问题。本文将针对钉钉数据恢复这一主题&#xff0c;…

windows下python opencv ffmpeg读取摄像头实现rtsp推流 拉流

windows下python opencv ffmpeg读取摄像头实现rtsp推流 拉流 整体流程1.下载所需文件1. 1下载rtsp推流服务器1.2 下载ffmpeg2. 开启RTSP服务器3. opencv 读取摄像头并调用ffmpeg进行推流4. opencv进行拉流整体流程 1.下载所需文件 1. 1下载rtsp推流服务器 下载 RTSP服务器 下…

pyqt+opencv+常用图像算法可视化[资源介绍]

包含的算法&#xff1a; 均值滤波高斯滤波中值滤波Sobel边缘检测Laplacian边缘检测Canny边缘检测膨胀腐蚀灰度化直方图均衡化 包含的功能&#xff1a; 从文件中打开图片返回上一张处理后的图像保存处理后的图像文件退出系统 系统界面&#xff1a; 见我的资源&#xff0c;ht…

大型网站系统架构演化实例_3.使用服务集群改善网站并发处理能力

1.使用服务集群改善网站并发处理能力 使用集群是网站解决高并发、海量数据问题的常用手段。当一台服务器的处理能力、存储空间不足时&#xff0c;不要企图去更换更强大的服务器&#xff0c;对大型网站而言&#xff0c;不管多么强大的服务器&#xff0c;对大型网站而言&…

数字零售力航母-看微软如何重塑媒体

数字零售力航母-看微软如何重塑媒体 - 从2024全美广播协会展会看微软如何整合营销媒体AI技术和AI平台公司 2024年&#xff0c;微软公司联合英伟达总司&#xff0c;赞助全美广播协会展会。本次展会微软通过搭建一个由全面的合作伙伴生态系统支持的可信和安全的平台&#xff0c;…

什么是301重定向,什么时候应该使用?301重定向详细说明

如果您将网站从一个URL移动到另一个URL&#xff0c;您需要采取必要的步骤来确保您的访问者被发送到正确的位置。在技术领域&#xff0c;这被称为301重定向。 在这里&#xff0c;我们将讨论什么是301重定向&#xff0c;何时需要使用&#xff0c;以及如何在网站或WordPress中重定…

【云计算】云计算八股与云开发核心技术(虚拟化、分布式、容器化)

【云计算】云计算八股与云开发核心技术&#xff08;虚拟化、分布式、容器化&#xff09; 文章目录 一、什么是云计算&#xff1f;1、云计算的架构&#xff08;基础设施&#xff0c;平台&#xff0c;软件&#xff09;2、云计算的发展 二、如何做云计算开发&#xff1f;云计算的核…

第十五届蓝桥杯复盘python大学A组——试题C 数字诗意

思路 数字可以分为 有诗意的数字可以写成 (ij)(j-i1)/2 &#xff08; i、j都是正整数 &#xff09; ij 、j-i1 的奇偶性不同&#xff08;因为i、j都是正整数&#xff09; 因此&#xff0c; 如果一个数是奇数就一定有诗意 eg.312 ,523,734,945… 原因&#xff1a;根据上述分…

PCIe错误报告机制

1 PCIe两种错误报告机制 Baseline Error Reporting (基线错误报告): 这是所有PCIe设备必须支持的基本错误报告机制。基线错误报告提供了一组基本的错误检测和报告功能&#xff0c;它包括的功能有&#xff1a; 错误检测&#xff1a;能够检测到不同类型的错误&#xff0c;例如数…

OpenCV从入门到精通实战(四)——答题卡识别判卷系统

基于OpenCV的答题卡识别系统&#xff0c;其主要功能是自动读取并评分答题卡上的选择题答案。系统通过图像处理和计算机视觉技术&#xff0c;自动化地完成了从读取图像到输出成绩的整个流程。下面是该系统的主要步骤和实现细节的概述&#xff1a; 1. 导入必要的库 系统首先导入…

三、fpga对完成过滤和校验的有效包数据进行有效像素提取、MATLAB对数据源进行处理与下发(完整实现pc机→显示器通信链路)

前言:上篇文章实现了MATLAB模拟发送UDP以太网协议数据包到fpga,能实现双沿数据→单沿数据转换,并将转换后的数据进行包过滤和crc校验,本篇内容要实现真正的从pc机下发视频数据,经过千兆以太网传输存储到fpga 的ddr3中,然后通过hdmi读出到显示屏上。 文章目录 一、模块设…

偏微分方程算法之一阶双曲差分法

目录 一、研究目标 二、理论推导 2.1 引言 2.2 迎风格式 2.3 完全不稳定差分格式 2.4 蛙跳格式&#xff08;Leapfrog&#xff09; 2.5 Lax-Friedrichs格式 2.6 Lax-Wendroff格式 2.7 Beam-Warming格式 2.8 隐格式 2.9 Courant-Friedrichs-Lewy条件&#xff08;CFL条…