【C++】动态内存管理new和delete

文章目录

  • 一、C++的内存管理方式
  • 二、new和delete的用法
    • 1.操作内置类型
    • 2.操作自定义内置类型
  • 三、new和delete的底层实现
    • 1.operator new和operator delete函数
    • 2.new和delete的实现原理
  • 四、定位new表达式
  • 五、malloc/free和new/delete的区别

一、C++的内存管理方式

之前在C语言的动态内存管理我们学过,用来动态开辟空间的malloc/calloc/realloc和释放空间的free。C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++将mallocfree封装起来并起了新的名字newdelete

二、new和delete的用法

1.操作内置类型

new和delete是操作符,不是函数,不需要单独添加头文件。

动态申请一个int类型的空间

int* p1 = (int*)malloc(sizeof(int));
int* p2 = new int;
//释放内存
free(p1);
delete p2;

动态申请一个int类型的空间并初始化

int* p3 = (int*)malloc(sizeof(int));
*p3 = 1;
int* p4 = new int(1);
//释放内存
free(p3);
delete p4;

动态申请10个int类型的空间

int* p5 = (int*)malloc(sizeof(int) * 10);
int* p6 = new int[10];
//释放内存
free(p5);
delete[] p6;

动态申请10个int类型的空间并初始化(C++11)

int* p7 = (int*)malloc(sizeof(int) * 10);
int* p8 = new int[10]{ 1,2,3 };//后面未初始化的部分默认为0
//释放内存
free(p7);
delete[] p8;

注意:申请和释放单个元素的空间,使用new/delete操作符;申请和释放连续的空间,使用new[ ]和delete[ ],一定要配套使用!

通过对比,明显new和delete的使用更方便简洁;可以发现malloc与new的几个区别:

1.malloc和free是函数,而new和delete是操作符
2.并且malloc申请空间时不会初始化,而new可以初始化,只需要在()(单个空间)或者{}(多个连续空间,C++11才引入)里赋值即可;
3.malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,如果是多个对象,[ ]中指定对象个数。
4.malloc的返回值为void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型

但是,这些优点并不足以解释C++不继续使用C语言的malloc和free,去创建一个新用法。new和delete最大的价值体现自定义类型的操作上。

2.操作自定义内置类型

对于内置类型,malloc/free与new/delete区别不大,真正的区别在于自定义类型

malloc/free与new/delete最大的区别是:申请自定义类型对象时,malloc是纯粹的开辟空间,不会初始化;而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。
在这里插入图片描述

对于需要资源申请的自定义类型更能体现其优势,以链表为例

在这里插入图片描述new会先开辟空间再调用构造函数初始化,delete会先调用析构函数清理资源再释放空间,这点是与malloc/free的最大区别,也是C++新增用法的主要原因。

三、new和delete的底层实现

1.operator new和operator delete函数

new和delete是用户进行动态内存申请和释放的操作符operator new 和operator delete是系统提供的全局函数,也是对malloc和free进行过封装的函数。

operator new和malloc的最大区别就是当申请错误时,处理的方式不一样。

malloc申请空间失败时会返回NULL
operator new函数实际通过malloc来申请空间,申请空间成功时直接返回失败则抛异常
在这里插入图片描述 new和delete是对operator new和operator delete这两个全局函数进行的封装。所以new/delete与malloc/free的不同:malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要判空,申请失败会抛异常。

2.new和delete的实现原理

new在底层调用operator new全局函数来申请空间,delete在底层调用operator delete全局函数来释放空间。

在这里插入图片描述通过反汇编可以看到,new先调用operator new(本质上是通过malloc)来申请空间,然后再调用构造函数进行初始化;delete先调用析构函数完成资源的清理,再调用operator delete释放空间。

对于内置类型

new和malloc,delete和free基本类似,不同的是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL

对于自定义类型

new原理:先调用operator new来申请空间,然后再调用构造函数进行初始化;
delete原理:先调用析构函数完成资源的清理,再调用operator delete释放空间。

在这里插入图片描述

四、定位new表达式

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

格式new(指针名)类型 或者 new(指针名)类型(参数值)

对于自定义类型的对象,需要使用new的定义表达式进行显示调用构造函数和析构函数进行初始化和资源清理。

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行A* pa = (A*)malloc(sizeof(A));new(pa)A;//显示调用构造函数//new(pa)A(10);pa->~A();//显示调用析构函数free(pa);return 0;
}

为什么要显示调用构造和析构?
因为pa是是指针类型,属于内置类型,不会自动调用构造和析构,所以需要显示调用。

定位new表达式在实际中一般是配合内存池使用。 内存池的工作原理是先向系统一次性申请比较大的空间,没有初始化,当我们每次去申请空间时就直接使用内存池里的空间,然后再进行初始化。

五、malloc/free和new/delete的区别

1.malloc和free是函数,new和delete是操作符;

2.malloc申请的空间不会初始化,new可以初始化;

3.malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[ ]中指定对象个数即可;

4.malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型;

5.malloc申请空间失败时返回NULL,因此使用时必须判空,new不需要判空,申请失败会抛异常;

6.申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

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

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

相关文章

kafka(四)消息类型

一、同步消息 1、生产者 同步发送的意思就是&#xff0c;一条消息发送之后&#xff0c;会阻塞当前线程&#xff0c;直至返回 ack。 由于 send 方法返回的是一个 Future 对象&#xff0c;根据 Futrue 对象的特点&#xff0c;我们也可以实现同 步发送的效果&#xff0c;只需在调…

【数据结构】计数排序等排序

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

C 语言实例 - 查找数组中最大的元素值

查找数组中最大的元素值。 实例 1 #include <stdio.h>int main() {int array[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};int loop, largest;largest array[0];for(loop 1; loop < 10; loop) {if( largest < array[loop] ) largest array[loop];}printf("最大…

Ubuntu系统中创建桌面快捷方式和添加Favorites

一. Ubuntu系统中创建软件的桌面快捷方式 Ubuntu桌面创建某个软件的桌面快捷方式&#xff0c;一个直观的方法。 方法1. 在图像界面下&#xff0c;一层一层地打开文件目录软件快捷方式/usr/share/applications/ 方法2. 或者在终端运行$ nautilus /usr/share/applications/ …

Django靓号管理系统:实现注销功能和重构视图

1. 重构项目结构 首先,我们需要重构项目结构,以更好地组织代码: 在​​web​​目录下创建一个新的​​views​​目录。在​​views​​目录中创建一个新文件​​account.py​​。删除原来的​​views.py​​文件。这样的结构更有利于代码的模块化和维护。 2. 更新 ​​url…

springcloud-config git配置源加载(部署公钥问题)

使用gitUrl作为配置源 gitee 或者github 中有类似于发布密钥的功能&#xff0c;允许通过私钥只读访问指定的仓库&#xff0c;文档中说的是 限制了git的操作为pull 和 clone。生成私钥的方式文档连接在此 https://gitee.com/help/articles/4181#article-header0 spring config只…

简过网:不懂就要问,什么叫考事业单位编制?

不懂就要问&#xff0c;什么叫考事业单位编制&#xff1f;考事业编就是纳入编制的事业单位招聘考试&#xff0c;本质上是还是一种招聘考试&#xff0c;由于是“铁饭碗”&#xff0c;福利好&#xff0c;待遇高&#xff0c;所以对于事业单位的考试一直受人关注。 ​ 一、什么是事…

深度分析 Apache Hudi:大数据实时处理的利器

什么是 Apache Hudi&#xff1f; Apache Hudi&#xff08;Hadoop Upsert Delete and Incremental&#xff09;是一个开源的数据湖存储框架&#xff0c;旨在在大规模数据集上提供高效的增量数据处理和实时数据更新能力。Hudi 由 Uber 开发&#xff0c;并于 2019 年捐赠给 Apach…

精准校准:深入解析scikit-learn中的StandardScaler

精准校准&#xff1a;深入解析scikit-learn中的StandardScaler 在机器学习中&#xff0c;特征缩放是一个至关重要的预处理步骤&#xff0c;它能够显著影响模型的性能。scikit-learn提供了一个强大的工具——StandardScaler&#xff0c;用于将数据标准化到单位方差和零均值。本…

MQ - RabbitMQ、SpringAMQP --学习笔记

什么是MQ&#xff1f; MQ 是消息队列&#xff08;Message Queue&#xff09;的缩写&#xff0c;它是一种应用程序间异步通信的技术。消息队列允许应用程序或服务间通过发送消息来交换数据&#xff0c;而不是直接调用对方&#xff0c;从而实现解耦、异步处理和负载均衡等目的。…

零成本打造精品宣传册

​随着互联网的发展&#xff0c;企业和个人对宣传册的需求日益增长&#xff0c;然而&#xff0c;高质量的宣传册制作往往需要不菲的成本。那么&#xff0c;如何零成本打造精品宣传册呢&#xff1f; 一、明确定位和目标群体 在制作宣传册之前&#xff0c;首先要明确其定位和目标…

qt pro文件常用配置

概述 记录一下常用的项目pro文件的一些常用配置 常用配置 QT core gui concurrent#添加concurrent并行处理模块 CONFIG windeployqt#打包部署&#xff0c;项目->构建步骤->Make参数 添加windeployqt&#xff0c;编译自动打包greaterThan(QT_MAJOR_VERSION, 4):…

Kafka入门到精通(三)-Kafka

Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。 这种动作&#xff08;网页浏览&#xff0c;搜索和其他用户的行动&#xf…

强化学习-3深度学习基础

文章目录 1 强化学习与深度学习的关系2 线性回归3 梯度下降4 逻辑回归5 全连接网络6 更高级的神经网络6.1 卷积神经网络6.2 循环神经网络6.3 transformer 将深度学习和强化学习结合起来&#xff0c;利用深度学习网络强大的拟合能力通过将状态、动作等作为输入&#xff0c;来估计…

JeecgBoot新建模块

引言 jeecg-boot设置了demo, system等默认模块。在二次开发中&#xff0c;常常需要进行模块扩展。比如新增一个订单模块或支付模块。如何准确的新增模块&#xff0c;在此文进行记录。 步骤 新建模块 在项目点击右键&#xff0c;新建模块。 如下图。 注意&#xff1a;报名需…

鸿蒙NEXT开发知识:工具常用命令—ohpm config

设置ohpm用户级配置项。 命令格式 ohpm config set <key> <value> ohpm config get <key> ohpm config delete <key> ohpm config list 说明 配置文件中信息以键值对<key> <value>形式存在。 功能描述 ohpm 从命令行和 .ohpmrc 文件中…

Linux命令----wc,uniq,sort的用法

1.wc的用法&#xff1a;wc 命令用于计算文件中的行数、单词数和字节数。 常用选项 -l&#xff1a;只显示行数-w&#xff1a;只显示单词数-c&#xff1a;只显示字节数-m&#xff1a;只显示字符数&#xff08;与 -c 类似&#xff0c;但处理多字节字符&#xff09;-L&#xff1a…

day22--77. 组合+216.组合总和III+17.电话号码的字母组合

一、77. 组合 题目链接&#xff1a;https://leetcode.cn/problems/combinations/ 文章讲解&#xff1a;https://programmercarl.com/0077.%E7%BB%84%E5%90%88.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1ti4y1L7cv 1.1 初见思路 组合问题用回溯学会使用剪…

SpringBoot:SpringBoot中调用失败如何重试

一、引言 在实际的应用中&#xff0c;我们经常需要调用第三方API来获取数据或执行某些操作。然而&#xff0c;由于网络不稳定、第三方服务异常等原因&#xff0c;API调用可能会失败。为了提高系统的稳定性和可靠性&#xff0c;我们通常会考虑实现重试机制。 Spring Retry为Spri…

基于 Triton Inference Server 的算法工程

如何将算法部署在 Triton Inference Server 基于Python后端的基础模型 (基础示例) 编写配置 config.pbtxt 以目标检测为例 定义输入输出: 参数名, 参数类型, 参数维度 name: "object_detect" # 模型名称, 与当前目录文件名一致 backend: "python" # 推…