new和delete用法详解

news2024/11/17 3:44:54

 

  本篇文章对C++中的new和delete进行详解。在讲解new和delete时,我们会对比C语言中的malloc和free,看看两者的区别和相似之点。希望本篇文章会对你有所帮助。

文章目录

一、什么是new和delete

二、new和delete的用法

2、1 new和delete操作内置类型

2、2 new和delete操作自定义类型

三、new和delete的底层实现

3、1 new的底层实现

3、2 delete的底层实现

三、总结


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:C++、高频面试问题 👀

💥 标题:new和delete用法详解 💥

 ❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️ 

一、什么是new和delete

  我们知道在C语言中,动态开辟内存的方法是使用:malloc/calloc/realloc。释放动态开辟的内存是free

  在C++中,又引出了一个新玩法:new 和 delete。在C++中,new是用来动态开辟内存的,delete是用来释放我们所动态开辟的内存。

  了解到了new和delete的是干什么的后,这里我们又有疑问了:C语言中已经有了malloc 和 free 了,直接延续用C语言的就行了,为什么还要新出一个用法呢?带着疑问,我们接着往下看。

二、new和delete的用法

2、1 new和delete操作内置类型

  在C语言中,对内置类型的动态开辟我们经常使用的函数是malloc函数。在C++中,我们也可以使用new操作符来动态申请空间。注意:我们这里发现了malloc 和 new 的第一个区别,malloc是函数,new是一个操作符当然,成对出现的free 是函数,delete 是操作符。我们先看其实用方法的对比,代码如下:

void Test()
{
  // 动态申请一个int类型的空间
  int* p1 = malloc(sizeof(int));
  int* p2 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* p3 = malloc(sizeof(int));
  *p3=10;
  int* p4 = new int(10);
  
  
  // 动态申请10个int类型的空间
  int* p5 = malloc(sizeof(int)*3);
  int* p6 = new int[3];
  
  //释放
  free(p1);
  delete p2;

  free(p3);
  delete p4;

  free(p5);
  delete[] p6;

}

  通过上面的使用对比,我们可以很明显的感觉到new和delete使用起来更加方便。因为我们在使用new动态开辟空间时,并不需要计算所开辟空间类型的大小。因为后面跟着类型,new会自动计算出类型的大小

  我们还发现,new在动态开辟内存时,还可以对其进行初始化。而malloc开辟后,才可通过解引用对其进行初始化。new在动态开辟数组时,也可对其进行初始化,但是这只是C++11才开始支持的语法,用法如下:

    int* p6 = new int[10]{1,2,3};
    delete[] p6;

  后面没有给出的值,会自动初始化为0。

  通过上面发现,new和delete使用起来确实方便一点。但是这好像并不足以解释C++不直接延续用C语言的用法,又新出一个用法。我们接着往下看。

2、2 new和delete操作自定义类型

  在C语言中,malloc动态申请自定义类型空间时,并不能对其进行很好的初始化。而是申请完后,需要我们自己对其进行初始化。对其变量进行赋值或调用其构造函数,我们在平常中也很容易忽略初始化这一点。

  在C++中,使用new对自定义类型进行操作申请空间时,会自动调用自定义类型默认的构造参数对自定义类型进行初始化。我们可看如下实例:

#include<iostream>

using namespace std;


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

	A(const A& a)
	{
		cout << "A(const A& )" << endl;
	}

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

};

int main()
{
	A* p1 = new A;
	delete p1;

	return 0;
}

  其运行结果如下:

  我们在通过调试看看到底是否对成员变量_a进行了初始化,结果如下:

  通过上面发现,还挑用了析构函数。注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与 free不会 。

  我们之前学习的链表更能体现出。链表是需要动态申请节点,此时new更能体先出其优势,我们可结合下面代码一起理解:

struct ListNode
{
    int _val;
    struct ListNode* _next;

    ListNode(int x)
        :_val(x)
        ,_next(NULL)
    {}
};

struct ListNode* BuyListNode(int x)
{
    // 单纯开空间
    struct ListNode* newnode = (struct ListNode*)malloc(sizeof(struct ListNode));
    // 检查
    newnode->_next = NULL;
    newnode->_val = x;

    return newnode;
}

int main()
{
    struct ListNode* n1 = BuyListNode(1);
    struct ListNode* n2 = BuyListNode(2);
    struct ListNode* n3 = BuyListNode(3);

    // 开空间+调用构造函数初始化
    ListNode* nn1 = new ListNode(1);
    ListNode* nn2 = new ListNode(2);
    ListNode* nn3 = new ListNode(3);

    return 0;
}

  new最主要的就是在操作自定义类型时可以去调用其构造函数对其进行初始化,malloc是做不到的。这也是C++新增用法的主要原因。

  通过上面的学习,发现new和malloc时是有点相似的,那么new的底层到底是怎么实现的呢?

三、new和delete的底层实现

3、1 new的底层实现

  new的底层其实就是用malloc进行实现的开辟空间,只不过是又多了一点东西。我们可结合下述代码理解一下:

#include<iostream>
using namespace std;

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

	A(const A& aa)
		: _a(aa._a)
	{
		cout << "A(const A& aa):" << this << endl;
	}

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

private:
	int _a;
};

int main()
{
	A* p1 = (A*)malloc(sizeof(A));
	A* p2 = new A(1,1);
	free(p1);
	delete p2;

	return 0;
}

  我们对上述代码进行调试,看其汇编代码:

  通过上图的汇编代码,我们看到new是先去调用了operator new函数再调用了自定义类型的构造函数。 我们再看看operator new函数里面的具体内容,如下:

  通过operator new函数我们可以看出,new的底层确实是用的malloc进行实现的。同时,new不用担心动态开辟空间失败,因为失败时会抛出异常,可让用户看到。但是malloc动态开辟空间失败后返回空指针,这就会给我们造成很大的麻烦,同时也不宜找出错误。

3、2 delete的底层实现

  delete的底层实现是通过free函数进行实现的。 我们一样结合new的底层实现给出的代码来看一下其汇编代码:

  通过汇编,我们可看到delete操作符先调用自定义类型的析构函数,再去调用operator delete 函数。我们再看operator delete 函数的内容。

   我们也看到,delete函数底层是用free函数实现的。

  通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果
malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。

三、总结

  通过上面的学习后,我们总结一下new/deletehe对不同类型实现原理的区别:
  • 对内置类型
  1. 如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是: new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
  • 对自定义类型new的原理
  1. 调用operator new函数申请空间;
  2. 在申请的空间上执行构造函数,完成对象的构造;
  • 对自定义类型newT[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对
    象空间的申请。
  2. 在申请的空间上执行N次构造函数
  • 对自定义类型delete的原理
  1. 在空间上执行析构函数,完成对象中资源的清理工作。
  2. 调用operator delete函数释放对象的空间。
  • 对自定义类型delete[]的原理
  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释
    放空间。

  最后,总结出malloc/freenew/delete的区别:

  1. malloc和free是函数,new和delete是操作符;
  2. malloc申请的空间不会初始化,new可以初始化;
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可;
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型;
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常;
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new 在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

  以上就是整个new和delete的讲解,感谢阅读ovo~ 

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

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

相关文章

中青宝两大议案被否!散户又“赢了”?

21.93万股&#xff0c;就能决定股东大会上的议案成败——离奇的一幕在中青宝上演。 5月18日&#xff0c;中青宝召开2022年度股东大会。会上&#xff0c;《关于2023年度日常关联交易预计的议案》《关于非独立董事2023年度薪酬方案的议案》两项议案被否。 此次股东大会上&#x…

linux设置静态ip与windows互相ping通、设置静态ip之后不能联网和网络服务重启失败的问题

1.虚拟机linux设置静态ip与windows互相ping通及设置静态ip之后不能联网问题一站式解决&#xff1a; 转载&#xff1a;https://www.codenong.com/cs105332412/ 2.遇到网络服务重启失败的问题 按照提示查看网络服务的状态 看到这篇博文https://www.cyberithub.com/failed-to-s…

Ae 效果详解:Keylight(1.2)

Ae菜单&#xff1a;效果/Keying/Keylight(1.2) Effects/Keying/Keylight(1.2) Keylight 是一款工业级的蓝幕或绿幕键控器&#xff0c;核心算法由 Computer Film 公司开发&#xff0c;并由 The Foundry 公司进一步开发移植到 Ae。 Keylight 在制作专业品质的抠像效果方面表现出色…

第11章_数据处理之增删改

第11章_数据处理之增删改 1. 插入数据 1.1 实际问题 解决方式&#xff1a;使用 INSERT 语句向表中插入数据。 1.2 方式1&#xff1a;VALUES的方式添加 使用这种语法一次只能向表中插入一条数据。 情况1&#xff1a;为表的所有字段按默认顺序插入数据 INSERT INTO 表名 VAL…

Python 学习 2022.08.28 周日

文章目录 一、 概述1.1&#xff09; 之前写的文章&#xff1a;1.2) 基础点1.3) 配置1.4) Python2 和 Python3 的区别1.5&#xff09; 相关问题跟踪解决1.6) 其他 一、 概述 1.1&#xff09; 之前写的文章&#xff1a; 【Python大系】Python快速教程《Python 数据库 GUI CGI编…

clion开发stm32之flash驱动(f4系列)

前言 使用的开发工具(clionmsys2openocd)使用的开发版芯片stm32f407vet6参考手册为stm32f4中文参考文档 查看中文手册 ## 驱动代码 头文件(bsp_flash.h) #ifndef STM32F103VET6_PROJECT_BSP_FLASH_H #define STM32F103VET6_PROJECT_BSP_FLASH_H #include "sys.h"…

华硕幻X 2023 Windows11原厂预装系统 工厂恢复安装带ASUSRecevory一键还原

华硕幻X 2023 Windows11原厂预装系统 工厂模式恢复安装带ASUSRecevory一键还原 文件地址&#xff1a;https://pan.baidu.com/s/1snKOsH3OMl3GZLqeAf-GLA?pwd8888 华硕工厂恢复系统 &#xff0c;安装结束后带隐藏分区以及机器所有驱动软件 需准备一个16G左右空u盘进行恢复 …

chatgpt赋能Python-python3怎么用

Python3入门指南&#xff1a;从基础到进阶 Python是一款简单而强大的编程语言&#xff0c;具有易读性、易学性和高生产性的特点。它广泛应用于数据分析、机器学习、Web开发、自动化测试等领域。Python的第三个版本&#xff08;Python3&#xff09;相对于第二个版本&#xff08…

网络互连与互联网 - 路由信息协议(RIP)

文章目录 1 概述2 RIP 要点2.1 根据 距离矢量&#xff08;或 跳数&#xff09;寻找最佳路由2.2 RIP 三大要点2.3 基本工作过程2.4 路由条目的更新规则2.5 RIPv1 和 RIPv2 区别2.6 "坏消息传播慢" 的问题 3 网工软考真题 1 概述 #mermaid-svg-DFp89TU9n8BiJLTr {font-…

K8s scheduler 调度:NodeName、NodeSelector与Taint

1 前言 上篇介绍了k8s调度的预选和优选策略&#xff0c;K8s scheduler 调度&#xff1a;预选和优选策略。 本篇介绍三个影响pod调度的配置&#xff1a;NodeName、NodeSelector与Taint。 2 NodeName NodeName是根据node的名称调度pod。可用于强制约束Pod跳过默认的Kubernetes调度…

Hive on Spark调优(大数据技术6)

第6章 Join优化 6.1 Hive Join算法概述 Hive拥有多种join算法&#xff0c;包括common join&#xff0c;map join&#xff0c;sort Merge Bucket Map Join等。下面对每种join算法做简要说明&#xff1a; 1&#xff09;common join Map端负责读取参与join的表的数据&#xff…

Hive on Spark调优(大数据技术8)

第8章 任务并行度优化 8.1 优化说明 对于一个分布式的计算任务而言&#xff0c;设置一个合适的并行度十分重要。在Hive中&#xff0c;无论其计算引擎是什么&#xff0c;所有的计算任务都可分为Map阶段和Reduce阶段。所以并行度的调整&#xff0c;也可从上述两个方面进行调整。 …

Maven基础学习---3、Maven的使用(命令行)

1、根据坐标创建Maven工程 1、Maven核心概念&#xff1a;坐标 &#xff08;1&#xff09;数学中的坐标 使用x、y、z三个[向量]作为空间的坐标系&#xff0c;可以在[空间]中唯一定位到一个[点]。 &#xff08;2&#xff09;Maven中的坐标 1、向量说明 使用三个[向量]在[Maven…

MapReduce排序

MapTask和ReduceTask均会对数据按照key进行排序。该操作属于Hadoop的默认行为。任何应用程序中的数据均会被排序&#xff0c;而不管逻辑上是否需要。 默认排序是按照字典顺序排序&#xff0c;且实现该排序的方法是快速排序。 对于MapTask&#xff0c;它会将处理的结果暂时放到…

25 SQL ——标量子查询

create table dept(id int primary key auto_increment,name varchar(15))comment 部门;insert into dept(id, name) values (1,研发部),(2,市场部),(3,财务部),(4,销售部),(5,总经办),(6,人事部);create table staff (id int primary key auto_increment commentID,name …

Java课设部署教程

这里我只演示使用IDEA软件或Eclipse两种常用的Java编译器的导入项目的教程&#xff01; IDEA部署教程 把下载的压缩包解压&#xff0c;解压后就是源码&#xff0c;打开IDEA&#xff0c;导入项目【源码】 选择源码所在的位置&#xff0c;点击ok即可导入 下面就是把源码导入到I…

(三)人工智能应用--深度学习原理与实战--神经网络的工作原理

机器学习是将输入(比如图像)映射到目标(比如标签“猫”)&#xff0c;并建立映射规则(即模型)。在深度学习中&#xff0c;神经网络通过一系列数据变换层来实现这种输入到目标的映射&#xff0c;本章节我们具体来看这种学习过程是如何实现的。 学习内容 1、理解层(Layer)及权重(…

【王道·计算机网络】第四章 网络层

一、 概述和功能 1.1 网络层功能 主要任务&#xff1a;把分组从源端传到目的端&#xff0c;为分组交换网上的不同主机提供通信服务传输单位&#xff1a;数据报功能&#xff1a; 路由选择与分组转发&#xff0c;即选择最佳路径异构网络互联(依靠路由器)拥塞控制(所有结点都来不…

基于PyQt5的图形化界面开发——自制ssh工具

基于PyQt5的图形化界面开发——自制ssh工具 0. 前言1. 第三方库的安装2. ssh原理3. 完整代码4. 演示效果5. 其他PyQt文章 0. 前言 本节我们使用PyQt5来制作一个简单的ssh小工具。 操作系统&#xff1a;Windows10 专业版 开发环境&#xff1a;Pycahrm Comunity 2022.3 Pytho…

设计模式中的UML基础

目录 1、UML概述 2、UML的用途 3、UML的构成 4、UML图 5、UML类图 5.1、类的构成 5.2、类与类之间的关系 6、绘制UML图的软件工具 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycl…