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[ ]的原理
      • 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大小的空间并且初始化为0int* p3 = (int*)realloc(p2, sizeof(int) * 10);	//扩容,把大小扩大到10个int,并且转移空间地址到p31
}

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


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

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

1、开发效率高、稳定

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

void Test()
{// 动态申请一个int类型的空间int* ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 = new int(10);// 动态申请5个int类型的空间,并初始化为0int* ptr6 = new int[5];// 动态申请5个int类型的空间并初始化前3个空间,后面2个空间默认为0int* 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. 在申请的空间上执行构造函数,完成对象的构造
	A* p1 = new A(1);

2、delete的原理

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

3、new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  2. 在申请的空间上执行N次构造函数
  3. 返回开辟空间的地址
	A* p2 = new A[10];

4、delete[ ]的原理

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

delete[ ]底层原理

delete[]被设计用来释放多个连续的同构造空间,那么它需要获取两个信息:

  1. 被释放空间的位置——在delete[]后接的地址p2;
  2. 调用几次析构函数——在我们使用new[]的时候,会自动在存储信息的空间前面开一个空间用来记录该空间存储了多少个对象。

如下代码:

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

我们使用了new A[10]开辟了十个存储int数据的空间,我们的指针p2也指向了这个空间的第一个元素的地址;
而当我们调用delete[]来释放该空间时,delete[ ]空着的[ ]就会把p2前面四个字节的内容作为整形装到[]里面,于是在编译器看来 delete[] p2 就变成了 “ delete[10] p2” ;
由此编译器知道了需要调用十次析构函数释放该空间,同时p2也被修改指向了该空间真正的起始地址,最后释放空间时会把开头的4个字节和后面的40个字节一起释放掉,然后p2被置空。至此new A[10]所占用的空间被全部释放;

在这里插入图片描述

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

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

相关文章

中间件系列 - Redis入门到实战(基础篇)

前言 1.学习视频&#xff1a; 黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目 2. 本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删除 3. 本章学习目标&#xff1a; 初始Redis 认识NoSQL认识Redi…

C++STL库的 deque、stack、queue、list、set/multiset、map/multimap

deque 容器 Vector 容器是单向开口的连续内存空间&#xff0c; deque 则是一种双向开口的连续线性空 间。所谓的双向开口&#xff0c;意思是可以在头尾两端分别做元素的插入和删除操作&#xff0c;当然&#xff0c; vector 容器也可以在头尾两端插入元素&#xff0c;但是在其…

【LeetCode刷题-树】-- 116.填充每个节点的下一个右侧节点指针

116.填充每个节点的下一个右侧节点指针 方法&#xff1a;层次遍历 /* // Definition for a Node. class Node {public int val;public Node left;public Node right;public Node next;public Node() {}public Node(int _val) {val _val;}public Node(int _val, Node _left, N…

利用anaconda中的Conda创建虚拟环境

目录 1. Anaconda 环境变量手动设置(详细)2. Conda 创建虚拟环境参考文献 1. Anaconda 环境变量手动设置(详细) 问题 Win键r打开运行对话框&#xff0c;输入cmd回车 输入conda&#xff0c;显示&#xff1a;‘conda’ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处…

gamit一(虚拟机启动不了)

Intel VT-x处于禁用状态怎么办-百度经验 1重新启动电脑 2找到电脑对应的品牌&#xff0c;联想G510是F2, 3进去BIOS&#xff0c;configure里面修改virtual为enable&#xff0c;回车 4F10保存&#xff0c;退出

【教3妹学编程-算法题】需要添加的硬币的最小数量

3妹&#xff1a;2哥2哥&#xff0c;你有没有看到新闻&#xff0c; 有人中了2.2亿彩票大奖&#xff01; 2哥 : 看到了&#xff0c;2.2亿啊&#xff0c; 一生一世也花不完。 3妹&#xff1a;为啥我就中不了呢&#xff0c;不开心呀不开心。 2哥 : 得了吧&#xff0c;你又不买彩票&…

HTML实现页面

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>工商银行电子汇款单</title> </head> &…

Ubuntu22.04 LTS + CUDA12.3 + CUDNN8.9.7 + PyTorch2.1.1

简介 本文记录Ubuntu22.04长期支持版系统下的CUDA驱动和cuDNN神经网络加速库的安装&#xff0c;并安装PyTorch2.1.1来测试是否安装成功。 安装Ubuntu系统 如果是旧的不支持UEFI启动的主板&#xff0c;请参考本人博客U盘系统盘制作与系统安装&#xff08;详细图解&#xff09…

1839_emacs中org-mode的代码结构

Grey 全部学习内容汇总&#xff1a; GitHub - GreyZhang/g_org: my learning trip for org-mode 1839_emacs中org-mode的代码结构 org-mode的代码结构主要是简单介绍一下如何让插入的代码片段具备源代码的处理属性&#xff0c;比如说以一定的语法进行显示、执行、被某些程序…

【探讨】bp神经网络是前馈还是后馈

目录 一、BP神经网络简介 1.1 什么是BP神经网络 1.2 BP神经网络的结构 二、BP神经网络的前馈与后馈 2.1 什么是BP神经网络的前馈 2.2 什么是BP神经网络的后馈 三、BP神经网络前馈与后馈的关系 3.1 BP神经网络前馈与后馈的区别 3.2 BP神经网络前馈与后馈的意义 四、BP…

php实现个性化域名(短网址)和个性化登录模版的解决方案

在PHP中&#xff0c;个性化域名通常指的是根据用户或业务需求动态生成具有特定规律的子域名。实现个性化域名的方法主要依赖于服务器配置和路由规则。下面是一些基本的步骤和考虑因素&#xff0c;以帮助你了解如何个性化域名&#xff0c;并了解这样做的好处。 如何实现个性化域…

注意力机制和自注意力机制

有很多自己的理解&#xff0c;仅供参考 Attention注意力机制 对于一张图片&#xff0c;我们第一眼看上去&#xff0c;眼睛会首先注意到一些重点的区域&#xff0c;因为这些区域可能包含更多或更重要的信息&#xff0c;这就是注意力机制&#xff0c;我们会把我们的焦点聚焦在比…

开源治理典型案例分享(汇编转)

当前&#xff0c;越来越多的企业申请通过信通院的开源治理成熟度评估和认证&#xff0c;获得增强级或先进级评估。这些企业包括中国工商银行股份有限公司、中国农业银行、上海浦东发展银行股份有限公司、中信银行股份有限公司、中国太平洋保险&#xff08;集团&#xff09;股份…

练练手之“四环”“磁铁”(svg)

文本是闲暇之余练习svg的运用的产物&#xff0c;记录以备有需。 <svg xmlns"http://www.w3.org/2000/svg" viewBox"0 0 500 500" width"500px" height"500px"><path d"M150,100 A50,50 0 1,1 150,99.999" stroke&q…

MySQL笔记-第07章_单行函数

视频链接&#xff1a;【MySQL数据库入门到大牛&#xff0c;mysql安装到优化&#xff0c;百科全书级&#xff0c;全网天花板】 文章目录 第07章_单行函数1. 函数的理解1.1 什么是函数1.2 不同DBMS函数的差异1.3 MySQL的内置函数及分类 2. 数值函数2.1 基本函数2.2 角度与弧度互换…

孩子还是有一颗网安梦——Bandit通关教程:Level 8 → Level 9

&#x1f575;️‍♂️ 专栏《解密游戏-Bandit》 &#x1f310; 游戏官网&#xff1a; Bandit游戏 &#x1f3ae; 游戏简介&#xff1a; Bandit游戏专为网络安全初学者设计&#xff0c;通过一系列级别挑战玩家&#xff0c;从Level0开始&#xff0c;逐步学习基础命令行和安全概念…

docker- 部署Jenkins集成Gitlab

目录 一、部署环境 二、获取镜像 三、配置maven 四、创建挂载目录 五、启动容器 六、Jenkins 初始化 七、相关插件安装与环境配置 八、Jenkins结合Gitlab进行构建及使用Gitlab钩子 一、部署环境 工具版本Docker20.10.14Jenkins2.396Gitlab14.8.2-eeJDK8、11Maven3.6…

Echarts小问题汇总

文章目录 Echarts小问题汇总1.柱状图第一条柱子遮挡Y轴解决方法2.在大屏渲染后 拖到小屏变模糊3.相邻柱状图中间不要有空隙4.实现echarts图表自适应5.单个柱状图最大宽度 Echarts小问题汇总 记录工作中使用Echarts的遇见的一些小问题&#xff0c;后续会不断进行补充 1.柱状图…

区块链实验室(31) - 交叉编译Ethereum的客户端Geth

编译Geth到X86架构平台 下载Geth源码&#xff0c;直接编译Geth源码&#xff0c;见下图。用file命令观察编译后的文件&#xff0c;架构是x86-64。 编译Geth到Arm64架构平台 直接用命令行编译&#xff0c;同时指定期望的架构为Arm64。编译脚本如下所示。 CGO_ENABLED0 GOOSlin…

vxe-table 右键菜单+权限控制(v3)

1.menu-config 是用于配置右键菜单的属性。通过 menu-config 属性&#xff0c;定义右键菜单的内容、显示方式和样式。 通过 menu-config 属性配置了右键菜单&#xff0c;其中的 options 属性定义了右键菜单的选项。用户在表格中右键点击时&#xff0c;将会弹出包含这些选项的自…