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

动态内存管理

  • 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;
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【前端面试3+1】13 JS特性、JS是单线程还是多线程、JS中的一部和同步、【合并两个有序数组】

一、JavaScript特性 弱类型&#xff1a;JavaScript是一种弱类型语言&#xff0c;变量的类型可以动态改变&#xff0c;不需要事先声明类型。动态性&#xff1a;JavaScript是一种动态语言&#xff0c;可以在运行时修改对象的结构和属性。基于原型的&#xff1a;JavaScript是一种基…

WdatePicker异常,无法弹出日期选择框

官网&#xff1a;My97日期控件官方网站 My97 DatePickerhttp://www.my97.net/ 可能使版本太老了&#xff0c;可以更新一下&#xff0c;然后根据官方的文件进行使用。 我的异常是因为在网上找的包里面缺少文件&#xff0c;去官网拉了一下最新的就行了。

状态压缩DP题单

P1433 吃奶酪&#xff08;最短路&#xff09; dp(i, s) 表示从 i 出发经过的点的记录为 s 的路线距离最小值 #include<bits/stdc.h> #define int long long using namespace std; const int N 20; signed main() { int n; cin >> n;vector<double>x(n 1),…

FreeRTOS之动态创建任务与删除任务

1.本文是利用FreeRTOS来动态创建任务和删除任务。主要是使用FreeRTOS的两个API函数&#xff1a;xTaskCreate()和vTaskDelete()。 任务1和任务2是让LED0、LED1闪烁。任务3是当按键按下时删除任务1。 使用动态创建任务时&#xff0c;需要动态的堆中申请任务所需的内存空间&…

OpenHarmony多媒体-ohos_videocompressor

介绍 videoCompressor是一款ohos高性能视频压缩器。 目前实现的能力&#xff1a; 支持视频压缩 使用本工程 有两种方式可以下载本工程&#xff1a; 开发者如果想要使用本工程,可以使用git命令 git clone https://gitee.com/openharmony-sig/ohos_videocompressor.git --…

Redis学习记录

Redis安装 首先是Redis的下载地址&#xff0c;事实上&#xff0c;Redis已经出到7的版本了&#xff0c;我们这里使用的是5的版本。&#xff08;3也能用&#xff09; Redis下载地址 我们将Redis下载下来并解压&#xff1a; 我们如何启动呢? redis-server.exe redis.windows.…

单分支:if语句

示例&#xff1a; /*** brief how about if? show you here.* author wenxuanpei* email 15873152445163.com(query for any question here)*/ #define _CRT_SECURE_NO_WARNINGS//support c-library in Microsoft-Visual-Studio #include <stdio.h>#define if_state…

学习笔记------约束的管理

此篇记录FPGA的静态时序分析&#xff0c;在学习FPGA的过程中&#xff0c;越发觉得对于时序约束只是懂了个皮毛。现在记录一下自己的学习过程。 本文摘自《VIVADO从此开始》高亚军 为什么要进行约束&#xff1f;约束的目的是什么&#xff1f; 简单来说&#xff0c;就是需要在…

Unity(MVC思想)

MVC 一下演示使用MVC和不使用MVC的做法区别。 前两个没有使用MVC 主面板逻辑&#xff1a; mainPanel是该脚本名字 每个场景中不一定存在该面板&#xff0c;单纯的显隐需要去手动挂载过于麻烦。 所以自己读取创建面板出来(每个场景仅创建一次)&#xff0c;存下该面板&#xf…

OpenHarmony网络请求库-httpclient

简介 HTTP是现代应用程序通过网络交换数据和媒体的的主要方式。httpclient是OpenHarmony 里一个高效执行的HTTP客户端&#xff0c;使用它可使您的内容加载更快&#xff0c;并节省您的流量。httpclient以人们耳熟能详的OKHTTP为基础&#xff0c;整合android-async-http&#xf…

FPGA核心板在声呐系统中的应用

前言 声纳系统使用声脉冲来探测、识别和跟踪水下物体。一个完整的声纳系统是由一个控制和显示部件、一个发射器电路、一个接收器电路和同时能作为发射装置&#xff08;扬声器&#xff09;和探测装置&#xff08;高灵敏度麦克风&#xff09;的传感器组成。 声纳系统图 技术挑战…

list基础知识

list 1.list 的定义和结构 list 是双向链表&#xff0c;是C的容器模板&#xff0c;其接收两个参数&#xff0c;即 list(a,b) 其中 a 表示指定容器中存储的数据类型&#xff0c;b 表示用于分配器内存的分配器类型&#xff0c;默认为 list <int>; list 的特点&#xff1a;…

鸿蒙开发岗突增!它和前端开发到底有哪些区别和联系?

2024年1 月 18 日&#xff0c;鸿蒙 Next 预览版面向开发者正式开放申请。至此&#xff0c;鸿蒙原生应用版图已成型&#xff0c;这个中国自主研发的操作系统&#xff0c;正式走上了独立之路。 有许多的公司都陆续地加入了鸿蒙原生应用开发的队列&#xff0c;从年初宣布的200个应…

MySQL高负载排查方法最佳实践(15/16)

高负载排查方法 CPU占用率过高问题排查 使用mpstat查看cpu使用情况。 # mpstat 是一款 CPU 性能指标实时展示工具 # 能展示每个 CPU 核的资源视情况&#xff0c;同时还能将资源使用情况进行汇总展示 # 如果CPU0 的 %idle 已经为 0 &#xff0c;说明此核已经非常繁忙# 打印所…

京西商城——前端项目的创建以及前后端联调

创建VUE项目 在jingxi_shop_project文件夹中再创建一个 frontend 文件夹用来存放前端项目 /jingxi_shop_project/backend/jingxi_shop_project....../frontend/jingxi_shop_web......首先要安装 node.js 和 VUE cli&#xff0c;进入到项目目录内创建项目 vue create jingxi_…

【JavaEE多线程】Thread类及其常见方法(上)

系列文章目录 &#x1f308;座右铭&#x1f308;&#xff1a;人的一生这么长、你凭什么用短短的几年去衡量自己的一生&#xff01; &#x1f495;个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C,自顶向下看Java-CSDN博客 ❤️相关文章❤️&#xff1a;清灵白羽 漾情天…

类和对象(中)(构造函数、析构函数和拷贝构造函数)

1.类的六个默认成员函数 任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 //空类 class Date{}; 默认成员函数&#xff1a;用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数 2.构造函数 构造函数 是一个 特殊的成员函数&a…

接口自动化入门: Http请求的域名与IP地址概念!

在进行接口自动化测试时&#xff0c;经常需要与服务器进行通信&#xff0c;这就涉及到了使用Http协议发送请求。在发送请求时&#xff0c;我们需要指定目标服务器的域名或者IP地址。下面将从0到1详细介绍域名与IP地址的概念及其在接口自动化测试中的应用。 本文从5个方面来书写…

3D可视化技术:研发基地的科技新篇章

在科技日新月异的今天&#xff0c;我们生活在一个充满无限可能性的时代。而在这个时代中&#xff0c;3D可视化技术正以其独特的魅力&#xff0c;引领着科技领域的新一轮变革。 3D可视化技术通过三维图像的方式&#xff0c;将现实世界或虚拟世界中的物体、场景等以立体、逼真的形…

改进下记录学习的小网站

Strong改进 结束&#xff1a;2024-4-14 打算投入&#xff1a;10h 实际消耗&#xff1a;12h 3m 学习总是不在状态。 我的时间花得很零散&#xff0c;也有点茫然。所以想尝试一下集中式地、一块一块地花&#xff0c;比如投入30个小时&#xff0c;去干一件事&#xff0c;这样就可…