C++学习笔记—— C++内存管理方式:new和delete操作符进行动态内存管理

系列文章目录

http://t.csdnimg.cn/d0MZH

目录

  • 系列文章目录
    • http://t.csdnimg.cn/d0MZH
  • 比喻和理解
    • a.比喻
      • C语言开空间
      • C++开空间
    • b.理解
      • a、C语言的内存管理的缺点
          • 1、开发效率低(信息传递繁琐)
          • 2、可读性低(信息展示混乱)
          • 3、稳定性差(开空间可能失败)
          • 代码演示
      • b、C++的内存管理方式的优点
          • 1、开发效率高、稳定
          • 2、可读性高(信息集中、整洁)
  • 一、C++又提出了自己的内存管理方式——通过new和delete操作符进行动态内存管理
    • 1. 我们在建开辟空间时会发现我们有4个核心需求:
    • 2. C++将开辟和释放分别集中在new和delete两个操作符实现:
    • 3. new集成:malloc、抛异常、构造函数;delete集成free、抛异常、析构函数
    • 4.new和delete内含的功能会根据具体的情况选择性发挥作用
  • 二、 operator new与operator delete函数
    • 1、 operator new与operator delete函数
  • 三、内置类型
  • 四、自定义类型
    • 1、new的原理
    • 2、delete的原理
    • 3、new T[N]的原理
    • 4、delete[ ]的原理


比喻和理解

C语言无法方便进行内存管理,C语言有关空间的所有操作都充满了冗余操作;
而C++通过new和delete操作符进行动态内存管理。
简而言之,C++对内存管理的创举主要是让我们输入的信息更高效的被编译器理解。

a.比喻

C语言开空间

打个比方,C语言开辟空间就像是:你要开席,你叫C语言去买10瓶可乐,C语言会做下面这些事:

  1. 问无效信息;
    它一次只买一瓶,重复十次买一瓶的操作,它每买一瓶都问你去哪家店买、走哪条路;

  2. 不会思考;
    买可乐的预算有多少,购买策略要你全部说清楚,购买时遇到意料之外的情况就打电话问你;

  3. 轻易放弃,结果不上报;
    如果C语言在去的第一家商店购买失败,它就不买了,也不会主动报告购买失败,需要我们专门询问,要是不问C语言就放任错误发生;

C++开空间

而C++就像是:你叫C++去买10瓶可乐,它会问你一些信息,然后再做以下事情:

  1. 主动思考
    C++会问你给它多少预算,给多少人喝,每人喝几杯,购买现场它根据这些信息自己决定购买策略。

  2. 灵活多变
    如C++在商店购买失败,它会自动换一家商店买。

  3. 有责任感
    换商店会一直换到成功为止,除非彻底买不到才打电话上报。


b.理解

a、C语言的内存管理的缺点

1、开发效率低(信息传递繁琐)
  1. 内存空间开辟需要显示定义
  2. 内存空间开辟代码编写繁琐
2、可读性低(信息展示混乱)
  1. 代码修改检查要反复对比
  2. 代码开空间显示不整齐
3、稳定性差(开空间可能失败)
  1. 就算声明了开空间,也不确定有没有开空间
  2. 开空间失败不自动报警,需要我们设置报警
代码演示

如下代码,我们的计划实现:

  1. 开一块空间存 int 类型的数据;
  2. 开辟这块空间并且初始化;
  3. 在原空间的基础上扩容;

为了实现以上功能,我们要写大量和我们的意图没有任何关系的内容。

代码演示:用C语言的方法开辟空间,可以看到这些代码是非常冗余的:

void Test()
{
	int* p1 = (int*)malloc(sizeof(int));	//开辟一个int大小的空间
	int* p2 = (int*)calloc(4, sizeof(int));	//开4个int大小的空间并且初始化为0
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);	//扩容,把大小扩大到10个int,并且转移空间地址到p31
}

糟糕的是上面三行代码如果开空间失败不会自动报警


b、C++的内存管理方式的优点

在实践时可以发现,我们编码时思维聚焦于开辟空间的用途
同时也发现,实现功能时会反复使用同样的空间大小和变量类型。

1、开发效率高、稳定

如下代码,我们要修改开辟的空间属性,只需要在开空间的代码上微调即可;

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr4 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr5 = new int(10);
  
  // 动态申请5个int类型的空间,并初始化为0
  int* ptr6 = new int[5];

  // 动态申请5个int类型的空间并初始化前3个空间,后面2个空间默认为0
  int* ptr7 = new int[5]={123};

  delete ptr4;
  delete ptr5;
  delete[] ptr6;
  delete[] ptr7;
}

简而言之,开辟一个空间,进行一番操作初始化它,就是我们的常做的操作;
由此,通过自定义类型就可以实现:通过一个类我们可以在开辟一个空间的同时启动一个构造函数对这个空间进行操作;
如下代码:
我们定义了一个自定义类型A,当我们使用new来开辟空间时,会自动启动A的构造函数;

#include<iostream>
using namespace std;
static int i = 1;

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A(" << i++ << "):" << this << endl;
	}

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

int main()
{
	// new/delete 和 malloc/free最大区别是 
	// new/delete对于【自定义类型】除了开空间,还会调用构造函数和析构函数
	A* p4 = new A(1);	// 开辟一个int空间
	A* p5 = new A[10]{1,2,3,4,5};
	A* p6 = new A[10];

	delete p4;
	delete[] p5;
	delete[] p6;
	return 0;
}


2、可读性高(信息集中、整洁)

在这里插入图片描述


一、C++又提出了自己的内存管理方式——通过new和delete操作符进行动态内存管理

1. 我们在建开辟空间时会发现我们有4个核心需求:

开辟空间(1、2),释放空间(3、4):

  1. 开辟空间;
  2. 初始化空间;
  3. 释放空间;
  4. 指针置空

2. C++将开辟和释放分别集中在new和delete两个操作符实现:

new实现:
1.开辟空间、2.初始化空间;

delete实现:
3.释放空间、4.指针置空;

在申请自定义类型的空间时,new会自动调用operator new和构造函数,delete会自动调用operator delete 和 析构函数。

3. new集成:malloc、抛异常、构造函数;delete集成free、抛异常、析构函数

  1. new 是operator new 和构造函数的结合, delete 是oprator delete 和析构函数的结合;
  2. perator new 是malloc和抛异常的结合,oprator delete 是free和抛异常的结合。

4.new和delete内含的功能会根据具体的情况选择性发挥作用

  1. 在new 起作用的过程中,固定发挥malloc、抛异常、构造函数初始化空间;
  2. 在delete 起作用的过程中,固定发挥free、抛异常的作用,根据情况来判断是否调用析构函数 释放空间;

如果开空间时没有malloc开辟空间,则当我们要释放空间时,我们可以去使用free或delete释放空间,因为此时delete只有free可以发挥作用,没有调用析构函数的必要;

如下代码:对p1象占用了int类型的空间,我们使用free就可以释放这个空间;
相同情况下,p2使用delete也是可以的;
同理,p3的int【10】也是free、delete皆可。

#include<iostream>
using namespace std;

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

private:
	int _a;
};

int main()
{
	// new和delete内含的功能会根据具体的情况选择性发挥作用
	A* p1 = new A(1);	//这里p1使用了int空间,我们delete或free释放即可
	A* p2 = new A(1);	//这里p2使用了int空间,我们delete或free释放即可
	free(p1);
	delete p2;

	A* p3 = new A[10];
	delete[] p3;



	return 0;
}

二、 operator new与operator delete函数

1、 operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。

如下代码我们尝试通过new来创建一个对象


#include<iostream>
using namespace std;

typedef char DataType;
class Stack
{
public:
	Stack(size_t capacity = 4)
	{
		cout << "Stack()" << endl;

		_array = new DataType[capacity];
		_capacity = capacity;
		_size = 0;
	}

	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		_array = nullptr;
		_size = 0;
		_capacity = 0;
	}

private:
	// 内置类型
	DataType* _array;
	int _capacity;
	int _size;
};

Stack* func()
 {
	int n;
	cin >> n;
	Stack* pst = new Stack(n);
	return pst;
}

int main()
{
	Stack* ptr = func();
	ptr->Push(1);
	ptr->Push(2);
	delete ptr;
	return 0;
}

在这里插入图片描述

三、内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:

  1. new/delete申请和释放的是单个元素的空间;
  2. new[ ]和delete[ ]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

四、自定义类型

1、new的原理

  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造

2、delete的原理

  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间

3、new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  2. 在申请的空间上执行N次构造函数

4、delete[ ]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是shell?

系统内核是操作系统的基本组成部分&#xff0c;它负责管理系统的硬件和软件资源&#xff0c;并提供一组基本的系统服务。内核是操作系统的核心&#xff0c;控制着计算机的所有主要功能&#xff0c;包括内存管理、进程管理、设备驱动程序、系统调用和安全防护等。内核在计算机中…

轻量封装WebGPU渲染系统示例<44>- 材质组装流水线(MaterialPipeline)之灯光和阴影(源码)

目标: 数据化&#xff0c;模块化&#xff0c;自动化 备注: 从这个节点开始整体设计往系统规范的方向靠拢。之前的都算作是若干准备。所以会和之前的版本实现有些差异。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sa…

前端点点点加载小点样式css动画过程实现

对话的 ... 加载动画&#xff0c;直接用 CSS 就可以实现&#xff0c;样式可以自己改&#xff0c;逻辑大差不差 <div class"loading-text"><span class"dot1"></span><span class"dot2"></span><span class&quo…

SSM整合——Springboot

1.0 概述 1.1 持久层&#xff1a; DAO层&#xff08;mapper&#xff09; DAO层&#xff1a;DAO层主要是做数据持久层的工作&#xff0c;负责与数据库进行联络的一些任务都封装在此 DAO层的设计首先是设计DAO的接口&#xff0c; 然后在spring-mapper.xml的配置文件中定义此接…

evo_res指令使用及各参数使用效果

目录 参数含义 效果演示 evo_res no_l.zip l.zip evo_res no_l.zip l.zip -v 输出相关指令 evo_res no_l.zip l.zip -p evo_res no_l.zip l.zip -p --plot_markers evo_res no_l.zip l.zip --save_plot ./plot.pdf evo_res no_l.zip l.zip --serialize_plot ./s…

利用冒泡排序了解如何将数组作为参数传递给函数

目录 前言:冒泡排序简介步骤动图演示 错误的冒泡排序函数数组名正确的冒泡排序函数 前言:冒泡排序 简介 冒泡排序是一种简单直观的排序算法。 它重复地访问要排序的数&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。访问数需要重复地进行直到…

js 生成分享码或分享口令

代码 function getShareToken(length) {var characters ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789;var shareToken ;for (var i 0; i < length; i) {var randomIndex Math.floor(Math.random() * characters.length);var randomChar character…

Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 is available

记录一次服务调用中的错误 背景&#xff1a;我使用了nacos2.x的版本&#xff0c;同时在同一台服务器的三个docker容器中部署了nacos1、2、3&#xff0c;并将它们连接到了同一个docker网络 错误&#xff1a;Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 …

每日一练【长度最小的子数组】

一、题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 二、题目解析 经…

家用儿童床欧盟CE认证EN716标准

一、标准适用范围 该标准规定了内部长度大于900mm但不超过1400mm的家用童床的安全要求。该安全要求适用于完全组装完毕待用的童床。可以转换成其它产品的童床&#xff08;如&#xff1a;可变产品、游戏床&#xff09;转换后应该符合相关欧洲标准。该标准不适用于提篮、婴儿床和…

用docker创建jmeter容器,如何实现性能测试?

用 docker 创建 jmeter 容器, 实现性能测试 我们都知道&#xff0c;jmeter可以做接口测试&#xff0c;也可以用于性能测试&#xff0c;现在企业中性能测试也大多使用jmeter。docker是最近这些年流行起来的容器部署工具&#xff0c;可以创建一个容器&#xff0c;然后把项目放到…

跨境独立站优势包括哪些?是否值得做呢?

跨境独立站的优势主要包括&#xff1a; 自主品牌建设&#xff1a;独立站可以更好地展示自主品牌形象&#xff0c;提高品牌知名度和美誉度。 独立域名&#xff1a;独立站可以拥有自己的域名&#xff0c;更加稳定和可信。 自主运营&#xff1a;独立站可以自主运营&#xff0c;包…

排序的简单理解(下)

4.交换排序 基本思想&#xff1a;所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置 交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 4.1 冒泡排序 冒泡排序&#xff08…

Python图像转PDF神器:教你一步到位实现自动化处理

什么是 img2pdf 库&#xff1f; img2pdf 是一个 Python 库&#xff0c;它可以让你轻松地把多张图像转换为 PDF 文件。它支持多种图像格式&#xff0c;如 JPG, PNG, GIF, BMP 等&#xff0c;并且可以自动调整图像的大小和方向&#xff0c;以适应 PDF 的页面大小和方向。它还可以…

剑指offer(C++)-JZ49:丑数(算法-其他)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 把只包含质因子2、3和5的数称作丑数&#xff08;Ugly Number&#xff09;。例如6、8都是丑数&#xff0c;…

鸿蒙开发之状态管理@State

1、视图数据双向绑定 鸿蒙开发采用的声明式UI&#xff0c;利用状态驱动UI的更新。其中State被称作装饰器&#xff0c;是一种状态管理的方式。 状态&#xff1a;指的是被装饰器装饰的驱动视图更新的数据。 视图&#xff1a;是指用户看到的UI渲染出来的界面。 之所以成为双向…

量化交易与人工智能:Python库的应用与效用

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 量化交易简介 量化交易是一种利用计算机算法执…

gdb使用

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握gdb的使用 > 毒鸡汤&#xff1a;这个世…

arkts编译报错-arkts-limited-stdlib错误【Bug已完美解决-鸿蒙开发】

文章目录 项目场景:问题描述原因分析:解决方案:适配指导案例此Bug解决方案总结项目场景: arkts编译报错-arkts-limited-stdlib错误。 我用Deveco studio4.0 beta2开发应用,报arkts-limited-stdlib错误 报错内容为: ERROR: ArKTS:ERROR File: D:/prRevivw/3792lapplica…

排序算法:【选择排序]

一、选择排序——时间复杂度 定义&#xff1a;第一趟排序&#xff0c;从整个序列中找到最小的数&#xff0c;把它放到序列的第一个位置上&#xff0c;第二趟排序&#xff0c;再从无序区找到最小的数&#xff0c;把它放到序列的第二个位置上&#xff0c;以此类推。 也就是说&am…