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

 个人主页: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.mzph.cn/pingmian/56356.shtml

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

相关文章

15.5 JDBC数据库编程5——DAO

目录 15.1.1 引言 实体类Product.java 异常类DaoException.java Dao.java ProductDao.java ProductDaoImpl.java ProductDaoTest.java 15.1.1 引言 Java是面向对象编程语言&#xff0c;主要操作对象&#xff0c;而关系数据库的数据并不是对象&#xff0c;Java程序插入…

linux线程 | 线程的控制(下)

前言&#xff1a; 本节内容是线程的控制部分的第二个小节。 主要是列出我们的线程控制部分的几个细节性问题以及我们的线程分离。这些都是需要大量的代码去进行实验的。所以&#xff0c; 准备好接受新知识的友友们请耐心观看。 现在开始我们的学习吧。 ps:本节内容适合了解线程…

动态内存管理(C语言 VS C++)

目录 一.动态内存管理的前置知识 1.栈区 a.栈区的特点 b.注意事项 2.堆区 a.堆区的特点 b.注意事项 3.全局/静态区 a.作用域和生命周期 b.注意事项 4.常量区 二.C语言动态内存管理 1.malloc 函数 a.接口简介与使用实例 b.注意要点 2.calloc 函数&#xff1a; 3.…

Flink Web UI 是使用和调试保姆级教程(持续更新)

Flink Web UI 是调试和监控 Flink 应用程序的重要工具&#xff0c;通过它&#xff0c;你可以实时查看正在运行的 Flink 任务的详细信息&#xff0c;包括作业的状态、性能指标、各子任务的运行情况、故障恢复情况等。Flink Web UI 的这些功能为开发者和运维人员提供了调试和优化…

软考系统分析师知识点十三:软件需求工程

前言 今年报考了11月份的软考高级&#xff1a;系统分析师。 考试时间为&#xff1a;11月9日。 倒计时&#xff1a;24天。 目标&#xff1a;优先应试&#xff0c;其次学习&#xff0c;再次实践。 复习计划第一阶段&#xff1a;扫平基础知识点&#xff0c;仅抽取有用信息&am…

FPGA采集adc,IP核用法,AD驱动(上半部分)

未完结&#xff0c;明天补全 IP核&#xff1a;集成的一个现有的模块 串口写好后基本不会再修改串口模块内部的一些逻辑&#xff0c;将串口.v文件添加进来&#xff0c;之后通过他的上层的接口去对他进行使用&#xff0c;所以我们打包IP&#xff0c;之后就不用去添加源文件了&a…

仿 Mac 个人网站开发 |项目复盘

一、前言 1.1 灵感来源 早年有幸看到国外大佬做的一个 基于 Web 的 Windows XP 桌面娱乐系统, 那时刚好有搭建一个个人博客的想法, 所以就想是否可以基于 WEB 实现一个仿 Mac UI 的个人博客, 以应用的形式来展示博客各个功能! 1.2 相关链接(求个 Star) 前端开源代码后端开源…

Linux之实战命令32:chroot应用实例(六十六)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

ali 231普通滑块82y版本

有需求可以联系博主 let v Died_in2021

【含开题报告+文档+PPT+源码】基于人脸识别的课堂考勤系统的设计与实现

开题报告 随着科技的不断发展&#xff0c;人脸识别技术已经逐渐渗透到各个领域&#xff0c;包括教育领域。传统的课堂考勤方式通常依赖于学生签到或教师手动记录&#xff0c;这种方式存在着许多不足之处&#xff0c;例如容易出现人为错误、耗费时间和资源等。为了解决这些问题…

诺贝尔经济学奖历史名单数据集(1969-2024年)

2024年诺贝尔经济学奖授予了达龙阿西莫格鲁&#xff08;Daron Acemoglu&#xff09;、西蒙约翰逊&#xff08;Simon Johnson&#xff09;和詹姆斯A罗宾逊&#xff08;James A. Robinson&#xff09;&#xff0c;以表彰他们在理解制度如何影响经济发展方面的贡献。&#xff08;“…

jmeter用csv data set config做参数化

在jmeter中&#xff0c;csv data set config的作用非常强大&#xff0c;用它来做批量测试和参数化非常好用。 csv data set config的常用配置项如下&#xff1a; Variable Names处&#xff0c;写上源文件中的参数名&#xff0c;用于后续接口发送请求时引用 Ignore first line…

泰克MDO3054示波器特性和规格Tektronix MSO3054 500M 四通道

Tektronix MDO3054 示波器&#xff0c;混合域&#xff0c;500 MHz&#xff0c;4 通道&#xff0c;5 GS/s 泰克 MDO3054 混合域示波器是终极 6 合 1 集成示波器&#xff0c;包括可选的集成频谱分析仪、任意函数发生器、逻辑分析仪、协议分析仪和数字电压表/计数器。泰克 MDO305…

python项目实战——下载美女图片

python项目实战——下载美女图片 文章目录 python项目实战——下载美女图片完整代码思路整理实现过程使用xpath语法找图片的链接检查链接是否正确下载图片创建文件夹获取一组图片的链接获取页数 获取目录页的链接 完善代码注意事项 完整代码 import requests import re import…

Java算术运算符 C语言的二维数组初始化

1. //算术运算符 public static void main(String[] args) {System.out.println(3.25.01);//若有小数参与&#xff0c;有可能不精确System.out.println(5-1);System.out.println(5*2);System.out.println(10.0/3);//这里不精确System.out.println(10%2);System.out.println();…

2024.10月16日- Vue.js(1)

一 VUE概述与环境搭建 1.1 Vue概述 1.1.1 简介 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款轻量级的用于构建用户界面的 渐进式的JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高…

Vivado - Aurora 8B/10B IP

目录 1. 简介 2. 设计调试 2.1 Physical Layer 2.2 Link Layer 2.3 Receiver 2.4 IP 接口 2.5 调试过程 2.5.1 Block Design 2.5.2 释放 gt_reset 2.5.3 观察数据 3. 实用技巧 3.1 GT 坐标与布局 3.1.1 选择器件并进行RTL分析 3.1.2 进入平面设计 3.1.3 收发器布…

堆排序(C++实现)

参考&#xff1a; 面试官&#xff1a;请写一个堆排序_哔哩哔哩_bilibiliC实现排序算法_c从小到大排序-CSDN博客 堆的基本概念 堆排实际上是利用堆的性质来进行排序。堆可以看做一颗完全二叉树。 堆分为两类&#xff1a; 最大堆&#xff08;大顶堆&#xff09;&#xff1a;除根…

Java-IO流使用场景

Java IO 流是Java编程中非常重要的组成部分,用于处理文件读写、网络通信等数据传输任务。 1. 字节流 1.1 读取文件 import java.io.FileInputStream; import java.io.IOException;public class ReadFileExample {public static void main(String[] args) {try (FileInputSt…

Unity实现自定义图集(一)

以下内容是根据Unity 2020.1.0f1版本进行编写的   Unity自带有图集工具,包括旧版的图集(设置PackingTag),以及新版的图集(生成SpriteAtlas)。一般来说,unity自带的图集系统已经够用了,但是实际使用上还是存在一些可优化的地方,例如加载到Canvas上的资源,打图集不能…