C++的 new 和 delete
文章目录
- 一、new 和 delete 的使用
- 二、operator new 和 operator delete 函数
- 三、new 和 delete 的实现原理
- 四、申请空间和释放空间应配套使用
- 五、定位 new 表达式
- 六、malloc/free 和 new/delete 的区别
C语言的动态内存管理函数(malloc、calloc、realloc、free) 虽然可以继续在 C++ 使用,但是对于自定义类型成员而言,这些函数不会自动调用构造函数和析构函数,于是 C++ 增加了 new 和 delete 关键字
一、new 和 delete 的使用
new 和 delete 用于在堆上申请或释放一个元素的空间,new[] 和 delete[] 用于在堆上申请或释放一块连续的空间,对于自定义类型空间的开辟,new 和 delete 还会调用构造函数和析构函数
#include <iostream>using namespace std;class Demo
{
public:Demo(int a1 = 10, int a2 = 20): _a1(a1), _a2(a2){cout << "Demo()" << endl;}void print(){cout << _a1 << " " << _a2 << endl;}~Demo(){cout << "~Demo()" << endl;}private:int _a1;int _a2;
};void printIntArr(int* arr, int len)
{for (int i = 0; i < len; ++i){cout << arr[i] << " ";}cout << endl;
}void printDemoArr(Demo* arr, int len)
{for (int i = 0; i < len; ++i){arr[i].print();}cout << endl;
}int main()
{//用 new 申请一个内置类型变量的空间int* pint1 = new int;cout << *pint1 << endl; //输出 -842150451//使用括号中的值初始化变量int* pint2 = new int(5);cout << *pint2 << endl; //输出 5//用 delete 释放一个变量的空间delete pint1;delete pint2;//用 new 申请一个自定义类型对象的空间,申请后会自动调用构造函数Demo* pd1 = new Demo; //输出 Demo()pd1->print(); //输出 10 20//自定义类型会根据括号中的参数调用对应的构造函数Demo* pd2 = new Demo(5, 5); //输出 Demo()pd2->print(); //输出 5 5//用 delete 释放一个变量的空间,释放前会自动调用析构函数delete pd1; //输出 ~Demo()delete pd2; //输出 ~Demo()//对内置类型用 new[] 开辟一块连续的空间int* pint3 = new int[5]; //[]中表示开辟整形的个数printIntArr(pint3, 5); //输出 -842150451 -842150451 -842150451 -842150451 -842150451//用花括号中的值初始化开辟的连续空间,未给值的为 0int* pint4 = new int[5]{ 1, 2, 3, 4 }; printIntArr(pint4, 5); //输出 1 2 3 4 0//对内置类型用 delete[] 释放一块连续的空间delete[] pint3;delete[] pint4;//对自定义类型用 new[] 开辟一块连续的空间//申请后会对空间自动调用构造函数 5 次Demo* pd3 = new Demo[5]; //输出 5 行 Demo()printDemoArr(pd3, 5); //输出 5 行 10 20//用花括号中的值初始化开辟的连续空间//花括号中如果用小括号会被认为是逗号表达式,会去调用单参的构造函数//调用多参构造函数应在花括号中使用花括号,未给的值根据构造函数决定Demo* pd4 = new Demo[5]{ (1, 2), {5}, {5, 10}}; //输出 5 行 Demo()printDemoArr(pd4, 5); //输出 第一行 2 20,第二行 5 10 第三行 5 10,两行 10 20//对自定义类型用 delete[] 释放一块连续的空间//释放之前会对空间自动调用析构函数 5 次delete[] pd3; //输出 5 行 ~Demodelete[] pd4; //输出 5 行 ~Demoreturn 0;
}
二、operator new 和 operator delete 函数
operator new 和 operator delete 是系统提供的全局函数,不是 new 和 delete 的运算符重载函数
-
operator new 底层是通过 malloc 函数来申请空间,当空间申请成功时直接返回,失败时抛出异常(不会返回 nullptr),operator new 函数可以像 malloc 一样使用,只是失败时的处理不同
-
operator delete 和 free 底层都是是通过 _free_dbg 函数释放空间,只不过 operator delete 会对释放前后进行一些检查
#include <iostream>using namespace std;int main()
{//operator new 和 malloc 使用方法一样//operator new 申请空间失败时抛异常int* pi = (int*)operator new(sizeof(int) * 4);//operator delete 和 free 使用方法一样,都会调用 _free_dbg//operator delete 在释放空间时会做一些检查operator delete(pi);return 0;
}
operator new[] 和 operator delete[] 也是系统提供的全局函数,内部是通过调用 operator new 和 operator delete 函数
三、new 和 delete 的实现原理
如果是内置类型,new 和 delete 调用 operator new 和 operator delete,new[] 和 delete[] 调用 operator new[] 和 operator delete[]
如果是自定义类型:
#include <iostream>using namespace std;class Demo
{
public:Demo(int a1 = 10, int a2 = 20);~Demo();private:int _a1;int _a2;
};Demo::Demo(int a1, int a2): _a1(a1), _a2(a2)
{cout << "Demo()" << endl;
}Demo::~Demo()
{cout << "~Demo()" << endl;
}int main()
{Demo* pd1 = new Demo(5, 5);delete pd1;Demo* pd2 = new Demo[2]{ {1, 2}, {2, 3} };delete[] pd2;return 0;
}
- new:
1. 调用 operator new 函数申请空间
2. 在申请的空间上执行构造函数,完成对象的构造 - delete:
1. 在空间上执行析构函数,完成对象中资源的清理工作
2. 调用operator delete函数释放对象的空间
- new 类型[N]:
1. 调用operator new[] 函数,实际上是在 operator new[] 中调用 operator new 函数完成 N 个对象空间的申请
2. 在申请的空间上执行 N 次构造函数 - delete[]:
1. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理
2. 调用 operator delete[] 释放空间,实际上时在 operator delete[] 中调用 operator delete 来释放空间
四、申请空间和释放空间应配套使用
malloc/free、new/delete、new[]/delete[] 需要配套使用,否则总会有出问题的时候
下述代码不会报错,会产生内存泄漏
#include <iostream>using namespace std;class Stack
{
public:Stack(int capacity = 4): _a(new int[capacity]), _top(0), _capacity(capacity){}~Stack(){if (_a){delete[] _a;_top = _capacity = 0;}}private:int* _a;int _top;int _capacity;
};int main()
{Stack* ps = new Stack;//free(ps); //内存泄漏//delete 释放内存之前会调用析构函数delete ps; //正确写法return 0;
}
下述代码在 vs2022 下会崩溃
#include <iostream>using namespace std;class A
{
public:A(int a = 0): _a(a){cout << "A():" << endl;}~A(){cout << "~A():" << endl;}private:int _a;
};int main()
{A* p1 = new A[10];//free(p1); //崩溃delete[] p1; //正确写法A* p2 = new A[10];//delete p2; //崩溃delete[] p2; //正确写法return 0;
}
注意:不同的编译器处理可能不同,这里只代表在 vs2022 编译器中
五、定位 new 表达式
定位 new 表达式是在已开辟好的原始内存空间上调用构造函数初始化一个对象,使用格式:
new(place_address)type 或者 new(place_address)type(initializer-list)
place_address 必须是一个指针,initializer-list 是类型的初始化列表
定位 new 表达式在实际中一般是配合 内存池 使用,因为内存池分配出的内存没有初始化,并且构造函数不可以显示调用,所以如果是自定义类型的对象,需要使用定位 new 以进行显示调用构造函数进行初始化
#include <iostream>using namespace std;class A
{
public:A(int a = 0): _a(a){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}private:int _a;
};//定位 new 又叫 replacement new
int main()
{//p1 现在指向的只是与 A 对象相同大小的一段空间,并不是一个对象,因为没有调用构造函数A* p1 = (A*)malloc(sizeof(A));new(p1)A; //调用无参的构造函数 输出 A()//可以手动调用析构函数,然后释放空间p1->~A(); //输出 ~A()free(p1);//p2 现在指向的只是与 A 对象相同大小的一段空间,并不是一个对象,因为没有调用构造函数A* p2 = (A*)operator new(sizeof(A));new(p2)A(10); //10 是参数,可以根据参数调用对应的构造函数 输出 A()p2->~A(); //输出 ~A()operator delete(p2);return 0;
}
六、malloc/free 和 new/delete 的区别
malloc/free 和 new/delete 的共同点是:都是从堆上申请空间,并且需要用户手动释放
不同的地方是:
- malloc 和 free 是函数,new 和 delete 是运算符
- malloc 申请的空间不会初始化,new 可以初始化
- malloc 申请空间时,需要手动计算空间大小并传递,new 只需在其后跟上空间的类型,如果是多个对象,[] 中指定对象个数即可
- malloc 的返回值为 void*,接收时必须强制类型转换,new 不需要,因为 new 后跟的是空间的类型
- malloc 申请空间失败时,返回的是NULL,因此使用时必须判空,new 不需要,但是 new 需要捕获异常
- 申请自定义类型对象时,malloc/free 只会开辟空间,不会调用构造函数与析构函数,而 new 在申请空间后会调用构造函数完成对象的初始化,delete 在释放空间前会调用析构函数完成空间中资源的清理
相关文章:

C++的 new 和 delete
文章目录一、new 和 delete 的使用二、operator new 和 operator delete 函数三、new 和 delete 的实现原理四、申请空间和释放空间应配套使用五、定位 new 表达式六、malloc/free 和 new/delete 的区别C语言的动态内存管理函数(malloc、calloc、realloc、free) 虽然可以继续在…...

MySQL 事务原理
文章目录1、事务1.1、ACID 特性1.1.1、原子性undo log1.1.2、一致性1.1.3、* 隔离性1.1.4、持久性redo log1.2、事务控制语句2、隔离级别2.1、隔离级别的分类2.1.1、读未提交 RU2.1.2、读已提交 RC2.1.3、可重复读 RR2.1.4、串行化 SC2.2、并发事务读异常2.2.1、* 脏读2.2.2、*…...

软件测试面试自我介绍/项目介绍居然还有模板?我要是早点发现就好了
目录 1、自我介绍 2、项目介绍 2.1、最全电商项目介绍 2.2、电商项目介绍 2.3、在线教育项目介绍 2.4、互联网金融项目介绍 总结 1、自我介绍 以XXX简历来举例(参照下面的案例,编写你的自我介绍,框架就是:我是谁࿰…...
new RegExp的使用
1.RegExp是什么 当检索某个文本时,可以使用一种模式来描述要检索的内容。RegExp 就是这种模式 RegExp 对象用于存储检索模式。 var patt1new RegExp("e");当使用该 RegExp 对象在一个字符串中检索时,将寻找的是字符 “e” g :表…...

供应商管理软件如何选型 好用的供应商管理软件推荐
供应商管理是采购中的重要环节。对于很多企业来说,做好内部供应商管理就能在行业竞争中提升自身的效益与竞争能力,供应商已成为一种战略筹码。 但在企业进行供应商管理过程中,往往会遇到供应商信息数据收集不全、等级划分不合理、绩效评价机…...

Python3遍历文件夹提取关键字及其附近字符
要求: 1,遍历文件夹下所有的.xml文件 2,从.xml文件中提取关键字以及左右十个字符 3,输出到excel 一:遍历文件夹找到所有xml文件及其路径 for root, dirs, files in os.walk(self.inputFilePath):for file in files:…...

「1」线性代数(期末复习)
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀 第一章 行列式 行列式是一个数,是一个结果三阶行列式的计算:主对角线的乘…...

C++7:STL-模拟实现vector
目录 vector的成员变量 构造函数 reserve size() capacity() push_back 一些小BUG 赋值操作符重载 析构函数 【】操作符重载 resize pop_back Insert 迭代器失效 erase 二维数组问题 总结一下 vector,翻译软件会告诉你它的意思是向量,但其…...

笑死,面试官又问我SpringBoot自动配置原理
面试官:好久没见,甚是想念。今天来聊聊SpringBoot的自动配置吧? 候选者:嗯,SpringBoot的自动配置我觉得是SpringBoot很重要的“特性”了。众所周知,SpringBoot有着“约定大于配置”的理念,这一…...

分布式缓存服务DCS-企业版性能更强,稳定性更高
背景介绍 近年来,随着各行业业务需求急速增加,数据量和并发访问量呈指数级增长,原来只能依附于关系型数据库的传统“缓存”逐渐难以支撑上层业务,开源Redis也面临着如“容量有限”、 “可靠性有限”、 “数据重复拷贝,…...
HTTP基本原理
目录URL简单定义格式HTTP和HTTPSHTTP的请求过程。请求响应响应体HTTP2.0总结URL 简单定义 通过一个链接,使我们可以找到网络上的某个资源,这个链接就是URL。 格式 URL并不是随便写的,而是有固定的格式。基本的组成格式如下。 schme://[us…...
【云原生】Kubernetes(k8s)最新版本详细保姆级安装教程
前言 Kubernetes简称k8s,是一个开源的,用于管理云平台中多个主机上的容器化的应用,k8s目标是让部署容器化的应用简单并且高效,k8s提供了应用部署,规划,更新,维护的一种机制。 本文是总结了在安…...

JVM - 类加载,连接和初始化
目录 类加载和类加载器 概述 类加载要完成的功能 加载类的方式 类加载器 类加载器的关系 类加载器说明 双亲委派模型 工作过程如下: 双亲委派模型说明: 破坏双亲委派模型: 类连接和初始化 类连接主要验证的内容 类连接中的解析…...

[carla]关于odometry坐标中的角度坐标系 以及 到地图的映射问题
1.获取车辆的Odometry原始信息 在carla中,通过订阅/carla/ego_vecle/odometry 可以查看车辆的全局位置信息,例如: > header: seq: 118872stamp: secs: 5946nsecs: 5720187frame_id: "map" child_frame_id: "ego_vehicle" pos…...
Python 正则表达式
正则表达式主要用来查找和匹配字符串的。 一、正在表达式基础 字符 描述 示例 TIY\ 示意特殊序列(也可用于转义特殊字符)如:空白字符 "\s" . 任何字符(换行符除外) "he..o" ^ 起始于 "^h…...

spark03-读取文件数据分区数量个数原理
代码val conf: SparkConf new SparkConf().setMaster("local").setAppName("wordcount")val sc: SparkContext new SparkContext(conf)val rdd: RDD[String] sc.textFile("datas/1.txt",2)rdd.saveAsTextFile("output")数据格式 &a…...

操作系统(day08)内存
存储单元 内存的几个基本概念 存储单元 内存地址从0开始,每个地址对应一个存储单元 存储单元大小根据计算机按照什么方式编址 按字节编址 则每个存储单元大小为一字节,即1B,即8个二进制位按字编址 看这个计算的字长是多少位,如…...

11- 聚类算法 (KMeans/DBSCAN/agg) (机器学习)
聚类算法 聚类算法和降维算法那都属于无监督算法。KMeans 是以一个值为中心, 然后所有其他点到该点距离最小值的累积和。 kmeans KMeans(n_clusters3) # n_clusters 分类数量 kmeans.fit(data.iloc[:,1:]) # 无监督,只需要给数据X就可以 DBSCAN 算法是…...

日日顺供应链|想要看清供应链发展趋势,先回答这三个问题
技术变革如何支撑供应链及管理服务的发展? 数字化与科技化开始承托供应链管理能力的升级与变革? 如何从客户需求的纬度反推供应链及管理服务的模式变革?在过去的三年中,我国的供应链企业经受了最为极端的挑战,但当下&a…...
5守护进程与线程
进程组 多个进程的集合,第一个进程就是组长,组长进程的PID等于进程组ID。 进程组生存期:进程组创建到最后一个进程离开(终止或转移到另一个进程组)。与组长进程是否终止无关。 一个进程可以为自己或子进程设置进程组 ID 相关函数 pid_t …...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版
1.题目描述 2.思路 当前的元素可以重复使用。 (1)确定回溯算法函数的参数和返回值(一般是void类型) (2)因为是用递归实现的,所以我们要确定终止条件 (3)单层搜索逻辑 二…...

Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...
在Spring Boot中集成RabbitMQ的完整指南
前言 在现代微服务架构中,消息队列(Message Queue)是实现异步通信、解耦系统组件的重要工具。RabbitMQ 是一个流行的消息中间件,支持多种消息协议,具有高可靠性和可扩展性。 本博客将详细介绍如何在 Spring Boot 项目…...