【C++学习手札】new和delete看这一篇就够了!

news2024/11/24 6:22:48

                                         食用指南:本文在有C基础的情况下食用更佳   

                                       🍀本文前置知识: C++类 

                                       ♈️今日夜电波: Prover—milet

                                                                1:21 ━━━━━━️💟──────── 4:01
                                                                    🔄   ◀️   ⏸   ▶️    ☰ 

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍 


目录

🌞引入—从C语言malloc、free到C++new、delete

🌔 一、new和delete语法定义

        new的语法定义

        delete的语法定义

        new的初始化

🌕二、给类对象申请空间(为什么说C++中要用new和delete)

        用malloc和用new给类申请空间的区别

         new申请对象数组

🌖三、一些注意事项

        delete void*可能会出错

        特别注意:malloc、free和new、delete 不可以混搭使用!

        使用 new 和 delete 采用相同形式


🌞引入—从C语言malloc、free到C++new、delete

        各位请先看下面这段代码:

void test1()//C语言动态管理空间
{
	int* p = NULL;

	p = (int*)malloc(sizeof(int));

	*p = 100;

	printf("%d\n", *p);
	free(p);
}

void test2()//C++动态管理空间
{
	int* p = NULL;

	p = new int(100);

	printf("%d\n", *p);
	delete p;
}

        这两段代码实现的功能是一样的。通过观察以及比对,我们很容易就能发现malloc和free分别对应着new和delete。乍一看,malloc、free和new、delete好像没什么区别?没错,他们的功能都是一样的,都是用来动态管理空间的。但是,如果细细观察,你会发现他们区别可大了!

         注意:

                1、new不需要强制类型转换。

                2、new可以在开辟空间时,可以同时初始化空间内容。

         \(^o^)/~ok,基本的引入就到这吧,现在我们进入正题,对于new、delete详解~


🌔 一、new和delete语法定义

        new的语法定义

//动态分配一个空间时
指针 = new 指针对应的类型;


//例1
int* ptr = new int;//在堆上分配一个整数的内存,并将其地址存储在指针ptr中


//申请多个空间时或者用于动态分配数组的内存时
指针 = new 指针对应的类型[申请的大小];

//例2

int* arr = new int[5];//在堆上分配一个包含5个整数的数组,并将其起始地址存储在指针arr中

        delete的语法定义

//当只开辟了一个空间时

delete 所要释放开间的指针

//例1
delete ptr;//释放空间


//申请多个空间时或者用于动态分配数组的内存时

delete 所要释放开间的指针

delete[] 所要释放空间的指针 //此释放该指针开辟的所有空间

//例2

delete arr;//可能只释放首个空间->不同编译器所为不同
delete[] arr;//全部释放

        特别注意:如果new和delete应当采用相同形式,详见本文末。

        new的初始化

//动态分配一个空间时
指针 = new 指针对应的类型(对应类型数值);

//例1
int* ptr = new int(100)//初始化空间值为100


//申请多个空间时或者用于动态分配数组的内存时
指针 = new 指针对应的类型[申请的大小]{数值(用,隔空)};

//例2
int* arr = new int[5]{1,2,3,4,5};//初始化5个空间值依次为1,2,3,4,5

        栗子:

void test2()//C++动态管理空间
{
	int* p = NULL;
	p = new int(100);
	printf("%d\n", *p);
	delete p;

	int* q = NULL;
	int* z = NULL;
	q = new int[5] {10, 20, 30, 40, 50};
	z = new int[5] {0};
	for (int i = 0; i < 5; i++)
	{
		cout << q[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < 5; i++)
	{
		cout << z[i] << " ";
	}
	delete[]z;
	delete[]q;
}

🌕二、给类对象申请空间(为什么说C++中要用new和delete)

        用malloc和用new给类申请空间的区别

        请看下面这段代码~

class A
{
public:
	int num;

public:

	A()
	{
		num = 200;
		cout << "构造函数" << endl;
	}

	~A()
	{
		cout << "析构函数" << endl;
	}
};

void test()
{
	A* p = (A*)malloc(sizeof(A));
	p->num = 100;
	cout << "malloc:num=" << p->num << endl;
	free(p);
	cout << endl;

	A* q = new A;
	cout << "new:num=" << q->num << endl;
	delete q;
}

        以下为该段代码的结果:

        很明显的能看到,如果我们使用malloc开辟空间以及free来释放空间,类中最经典的构造函数和析构函数都是没有被调用的!然而,使用new来申请空间 如果申请成功 就会自动调用 对应类的构造函数,在用delete释放空间时会自动调用析构函数!因此,在C++中,我们使用new和delete会比malloc和free安全的多!

         new申请对象数组

         请看下面这段代码~

class A
{
public:
	int num;

public:

	A()
	{
		num = 100;
		cout << "无参构造函数num="<<num << endl;
	}

	A(int n)
	{
		num = n;
		cout << "有参构造函数num="<<num << endl;
	}

	~A()
	{
		cout << "析构函数num="<<num << endl;
	}
};

void test()
{
	cout << "无参:" << endl;
	A* arr1 = new A[5];
	delete[]arr1;

	cout << endl;

	cout << "有参:" << endl;
	A* arr2 = new A[5]{A(1),A(2),A(3),A(4),A(5)};
	delete[] arr2;
}

          以下为该段代码的结果: 

         以上的代码分别为利用无参构造函数和有参构造函数构造的对象数组,从以上例子我们也可总结出以下几点要点:

        1、类对象数组本质是数组 只是数组的每个元素是类的对象。

        2、如果想让对象数组中的元素调用有参构造 必须人为使用 有参构造初始化。
        3、初始化的元素 调用有参构造 没有初始化的 调用无参构造。

        4、当创建一个对象数组的时候, 必须对数组中的每一个对象调用构造函数, 除了在栈
        上可以聚合初始化, 必须提供一个默认的构造函数。

        这里建议回顾回顾类的知识:  构造函数与析构函数 (这是链接,快点!)

在对象数组中:

        每个元素自动调用构造和析构函数,而他的构造顺序和析构顺序入下图所示:

         构造按照入上文例子中有参构造,从左往右,也就是说谁先定义谁先构造,而析构则是相反,谁最后定义谁最先析构!


🌖三、一些注意事项

        delete void*可能会出错

        如果对一个 void*指针执行 delete 操作, 这将可能成为一个程序错误, 除非指针指
向的内容是非常简单的, 因为它将不执行析构函数.以下代码未调用析构函数, 导致可用内存减少。
所以尽量不要用delete释放void *!

           栗子:

class Person {
public:

	Person(char* name, int age) 
	{
		pName = (char*)malloc(sizeof(name));
		strcpy(pName, name);
		mAge = age;
	}

	~Person() {
		if (pName != NULL) {
			delete pName;
		}
	}
public:
	char* pName;
	int mAge;
};
void test() {
	char arr[] = "john";
	void* A = new Person(arr, 22);
	delete A;
}

 特别注意:malloc、free和new、delete 不可以混搭使用!

        使用 new 和 delete 采用相同形式

        请仔细看下面这段代码~

    Person* person = new Person[10];
    
    delete person;

        以上代码有什么问题吗?
        这里使用了两个编译器来对该代码进行运行,分别出现了以下错误:vs 下直接中断、 qt 下析构函数调用一次
        使用了 new 也搭配使用了 delete, 问题在于 Person 有 10 个对象, 那么其他 9 个对象可能没有调用析构函数, 也就是说其他 9 个对象可能删除不完全, 因为它们的析构函数没有被调用。 我们现在清楚使用 new 的时候发生了两件事: 一、 分配内存; 二、 调用构造函数, 那么调用 delete 的时候也有两件事: 一、 析构函数; 二、 释放内存。 那么刚才我们那段代码最大的问题在于: person 指针指向的内存中到底有多少个对象, 因为这个决定应该有多少个析构函数应该被调用。 换句话说, person指针指向的是一个单一的对象还是一个数组对象, 由于单一对象和数组对象的内存布局是不同的。 更明确的说, 数组所用的内存通常还包括“数组大小记录”, 使delete 的时候知道应该调用几次析构函数。 单一对象的话就没有这个记录。

        单一对象和数组对象的内存布局可理解为下图:

        本图只是为了说明, 编译器不一定如此实现, 但是很多编译器是这样做的。 当我们使用一个 delete 的时候, 我们必须让 delete 知道指针指向的内存空间中是否存在一个“数组大小记录”的办法就是我们告诉它。 当我们使用 delete[ ], 那么 delete就知道是一个对象数组, 从而清楚应该调用几次析构函数。 结论: 如果在 new 表达式中使用[ ], 必须在相应的

delete 表达式中也使用[ ].如果在 new 表达式中不使用[], 一定不要在相应的 delete 表达式

中使用 [ ]。


                   感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                        

                                                                        给个三连再走嘛~   ​​​​​​​  

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

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

相关文章

OI易问卷协助企业服务好员工,收集员工反馈与信息

OI易问卷——企业问卷调查工具 OI易问卷&#xff0c;是群硕专为企业打造&#xff0c;对内服务员工的调查问卷。 集成于办公联合创新平台&#xff0c;并进一步帮助客户实现与微信或企业微信等其他平台的对接。 可以有效促进员工服务数字化&#xff0c;提高各部门工作效率&…

mysql的相关指令

mysql的相关指令 DML 数据操作语言DQL数据查询 mysql -uroot -p //启动数据库 show databases; //查看有哪些数据库 use 数据库名; //使用某个数据库 show tables; //查看数据库内有哪些表 exit; //退出mysql的命令环境 create database 数据库名称 charset utf8; //创建数据…

四项代表厂商,Kyligence 入选 Gartner 数据及人工智能相关领域多项报告

近日&#xff0c;全球权威的技术研究与咨询公司 Gartner 发布了《2023 年中国数据、分析及人工智能技术成熟度曲线》、《2023 年分析与商业智能技术成熟度曲线报告》、《2023 年数据管理技术成熟度曲线报告》&#xff0c;Kyligence 分别入选这三项报告的指标平台 Metrics Store…

【Git】 git push origin master Everything up-to-date报错

hello&#xff0c;我是索奇&#xff0c;可以叫我小奇 git push 出错&#xff1f;显示 Everything up-to-date 那么看看你是否提交了message 下面是提交的简单流程 git add . git commit -m "message" git push origin master 大多数伙伴是没写git commit -m "…

二维码查分系统制作方法大公开:用这个方法,你也可以快速拥有

自从“双减”政策颁布以来&#xff0c;学校对成绩的公布变得更加重视。尤其是小学年级&#xff0c;将成绩信息从分数制改为等级制进行发布。同时&#xff0c;成绩公布的方式也有了新的规定&#xff1a;禁止公开公布&#xff0c;不允许为学生成绩进行排名&#xff0c;并需要以特…

Java课题笔记~ ServletConfig

概念&#xff1a;代表整个web应用&#xff0c;可以和程序的容器(服务器)来通信 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://java.sun.com/xml/ns/javaee"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…

突破笔试:力扣129. 求根节点到叶节点数字之和

1. 题目链接&#xff1a;129. 求根节点到叶节点数字之和 给你一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。每条从根节点到叶节点的路径都代表一个数字&#xff1a;例如&#xff0c;从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 …

操作系统 -- 进程间通信

一、概述 进程经常需要与其他进程通信。例如&#xff0c;在一个shell管道中&#xff0c;第一个进程的输出必须传送给第二个进程&#xff0c;这样沿着管道传递下去。因此在进程之间需要通信&#xff0c;而且最好使用一种结构良好的方式&#xff0c;不要使用中断。在下面几节中&…

day3 STM32 GPIO口介绍

GPIO接口简介 通用输入输出接口GPIO是嵌入式系统、单片机开发过程最常用的接口&#xff0c;用户可以通过编程灵活的对接口进行控制&#xff0c;实现对电路板上LED、数码管、按键等常用设备控制驱动&#xff0c;也可以作为串口的数据收发管脚&#xff0c;或AD的接口等复用功能使…

ElasticSearch:项目实战(2)

ElasticSearch: 项目实战 (1) 需求&#xff1a; 新增文章审核通过后同步数据到es索引库 1、文章服务中添加消息发送方法 在service层文章新增成功后&#xff0c;将数据通过kafka消息同步发送到搜索服务 Autowiredprivate KafkaTemplate<String,String> kafkaTemplate;/…

【go语言学习笔记】04 Go 语言工程管理

文章目录 一、质量保证1. 单元测试1.1 定义1.2 Go 语言的单元测试1.3 单元测试覆盖率 2. 基准测试2.1 定义2.2 Go 语言的基准测试2.3 计时方法2.4 内存统计2.5 并发基准测试2.6 基准测试实战 3. 特别注意 二、性能优化1. 代码规范检查1.1 定义1.2 golangci-lint1.2.1 安装1.2.2…

网络基础2(HTTP,HTTPS,传输层协议详解)

再谈协议 在之前利用套接字进行通信的时候&#xff0c;我们都是利用 “字符串” 进行流式的发送接收&#xff0c;但是我们平常进行交流通信肯定不能只是简单的发送字符串。 比如我们用QQ进行聊天&#xff0c;我们不仅需要得到对方发送的消息&#xff0c;还要知道对方的昵称&…

Gitee+Jenkins(docker版)自动推送并部署Springboot项目到远程服务器

如果要参考gitlab配置请参考GitlabWebhook自动推送并更新Springboot项目 Gitlab的配置部分 环境介绍 Jenkins服务器(Centos7.6): docker安装的jenkins,参考Jenkins(docker安装)部署Springboot项目JDK1.8Maven3.6.3 注意docker安装的jenkins,而且是较新的版本,所以jenkins容器…

[足式机器人]Part4 机械设计 Ch00/01 绪论+机器结构组成与连接 ——【课程笔记】

本文仅供学习使用 本文参考&#xff1a; 《机械设计》 王德伦 马雅丽课件与日常作业可登录网址 http://edu.bell-lab.com/manage/#/login&#xff0c;选择观摩登录&#xff0c;查看2023机械设计2。 机械设计-Ch00Ch01——绪论机器结构组成与连接 Ch00-绪论0.1 何为机械设计——…

MySQL8是什么-MySQL8知识详解

从今天起&#xff0c;开始更新MySQL8的教程&#xff0c;今天更新MySQL8的第一篇文章&#xff0c;主要讲了MySQL8是什么、MySQL数据库的概念、MySQL的优势和MySQL的发展历史。 1、MySQL8是什么 MySQL 8是一个开源的关系型数据库管理系统。它是MySQL数据库的最新版本&#xff0c…

实例035 动画形式的程序界面

实例说明 在很多的程序界面中&#xff0c;都是以菜单或工具栏的形式显示窗体界面&#xff0c;这种显示方式是以静止状态显示的&#xff0c;界面不够生动。下面介绍一个以动画显示窗体界面的设计方法。运行本例&#xff0c;效果如图1.35所示。 技术要点 在该实例中用到了Micr…

0141 存储系统1

目录 3.存储系统 3.1存储器概述 3.2主存储器 3.3主存储器与CPU连接 部分习题 3.存储系统 3.1存储器概述 3.2主存储器 3.3主存储器与CPU连接 部分习题 1.设机器字长32位&#xff0c;一个容量为16MB的存储器&#xff0c;CPU按半字寻址&#xff0c;其可寻址的单元数是&…

P1941 [NOIP2014 提高组] 飞扬的小鸟

代码部分前有一千六百字了 P1941 [NOIP2014 提高组] 飞扬的小鸟 考察对背包 dp 算法过程理解的透彻性。过程透彻性也是解决所有问题的关键&#xff08;建立在算法已学的基础上&#xff09;。 n , m n,m n,m 的范围足够我们 O ( n m ) O(nm) O(nm) 的遍历整个地图。设 f i , …

【金融量化】对企业进行估值的方法有哪些?

估值的方法有哪些&#xff1f; 如何对企业进行估值&#xff1f;有2个方法估算。 1 绝对估值法 它是一种定价模型&#xff0c;用于计算企业的内在价值。 比如说你可以根据公司近N年的现金流情况。借此去预测未来N年的现金流情况。所有的现金流数据都可以在年报上查询到。最后…

TypeScript使用npm安装报错问题

问题如图&#xff1a; 问题原因&#xff1a; 权限不足导致&#xff0c;可以输入如下命令&#xff1a; sudo npm install i -g typescript该命令会要求输入登录密码相关&#xff0c;稍等片刻&#xff0c;即可安装成功。检测安装的命令&#xff1a; tsc -v