Learning C++ No.8【内存管理】
引言:
北京时间:2023/2/12/18:04,昨天下午到达学校,摆烂到现在,该睡睡,该吃吃,该玩玩,在一顿操作之下,目前作息调整好了一些,在此记录,2月11,开学之日,是比较搞笑、难忘的一天。简洁记录之后,此时我们就开始新知识的学习,一起来看一看什么是C++中的内存管理。
C++中的内存管理
复习C语言中的内存管理
谈到内存管理,我们必须要想到的就是内存的三个基本大区,栈区、堆区、静态区,但当我们一想到这些东西的时候,我们还应该想到的就是,C语言中的动态内存规划,谈到动态内存规划,此时我们就应该想到其中的4大天王,4个有关动态内存规划的函数,malloc、calloc、realloc,所以接下来我们就来复习看一下这三个函数的使用和特性。
函数 | 使用方法和特性 |
---|---|
malloc: | int*p1 = (int*)malloc(10*sizeof(int));不会初始化空间 |
calloc: | int*p1 = (int*)calloc(10,sizeof(int));会初始化空间 |
realloc: | int*p2 = (int*)realloc(p1,40);用于扩容场景 |
free: | 释放我动态开辟的空间 |
搞定了C语言中的知识之后,此时我们就开始我们C++中有关内存管理知识的学习啦!首先在我们内存中,我们的常量区也叫作数据区,并且我们的栈区是从高地址向低地址存放数据的,我们的堆区是从低地址向高地址存放数据的,如图所示:
所以此时我们就带着这幅图去学习一下什么C++中的内存规划,C++中的内存规划主要就是涉及到两个关键字,new和delete搞定了这两个关键字的特性和使用方法,我们就把C++中的内存规划给学的差不多了,首先,C++中为什么要提出new和delete这两个关键字呢?其实目的主要就是因为在C语言中并没有专门针对于自定义类型使用的内存开辟函数和释放函数,有的只是针对于内置类型的函数(malloc、realloc、malloc、free),并没有专门给自定义类型使用的函数,所以在我们的C++中有了类和对象的概念之后,自定义类型变得是更加的重要,所以为了专门给自定义类型的内存申请和释放,C++中就提出了new和delete这两个函数,并且我们的new和delete不仅针对自定义类型可以使用,对我们内置类型也是同样适用的,例如:int* p1 = new int;
意思就是开辟一个整形类型给p1指针,但注意,此时的该内存是没有被初始化的,只有这样写:int* p1 = new int(10);
此时的该整形内存才会被初始化为10,所以我们的new关键字开辟的空间,不管是自定义类型还是内置类型,此时你自己都是可以决定要不要进行初始化,决定初始化的值到底是给多少,所以这就是new的好处,不仅可以对所有类型开辟空间,还可以决定初始化,注意:此时上句代码一定要区别于下面这句代码:int* p1 = new int[10]
,上述代码的意思是开辟一个整形空间给p1,并且将该空间初始化为10,而该句代码的意思却是,开辟10个整形空间给p1,并且无初始化效果,若你想要有初始化效果,那么此时你就可以写成这样:int* p1 = new int[10] {1,2,3,4,5,6,7,8,9,10};
具体使用如图所示:
并且此时看见上述的代码是,我们要意识到,我们的new和delete要配套使用,malloc和free要配套使用,不可以交叉使用,不然会出问题。
总:new对于自定义类型的使用就是new+类型+圆括号(初始化)或者中括号(个数),对于自定义类型的使用就是,new单个对象就是调用构造函数,new多个对象就是调多次构造函数,所以new/delete和malloc/free最大的区别就是它们对于自定义类型使用时,new会自动调用构造函数,delete会自动调用析构函数。
operator new 和operator delete的使用
new是用户,也就是我们写代码的时候进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数(并不是什么重载,就是一个库里的函数而已),也就是编译器使用的函数,所以new申请空间使用的就是底层函数operator new,delete释放空间使用的就是底层函数operator delete,并且此时operator new 实际上使用的却又是malloc来申请空间,operator delete实际上使用的是free来释放空间,所以operator new和operator delete本质上就是malloc和free的封装。搞懂了这些,此时我们就再来看一下,C++中为什么要有new和delete。
再谈new出现的意义
1.要满足空间申请(因为C语言中已经有该功能,所以申请空间的功能就不需要重新实现了,直接原样的使用malloc就行)
2.满足自动调用构造函数去初始化自定义类型(C语言中没有该功能,所以该功能是需要自己去实现的,所以此时就要在malloc的基础之上再加上这一功能,这也就是new出现的原因)
所以在上述的基础上,我们就知道了new出现的原因,就是帮助用户去使用C语言中的malloc功能,并且实现自动调用构造函数的功能的一个封装函数。并且此时因为malloc失败之后返回的是空指针,不符合我们面向对象的过程,所以我们如果想要失败之后返回的是异常的话,就需要重新去写一个函数出来,该函数就是operator new,这也就是operator new出现的原因。所以operator new就是为了封装malloc前提下,也可以实现自动调用构造函数和开辟失败之后可以返回一个异常给我们而不是返回空指针的作用,这些适合自定义类型使用的开空间特性。所以这就是operator new出现的原因,当然此时的operator delete是同理如此使用的。只是此时delete在使用之前必须先调用析构函数而已,只有把所有的空间资源调用析构函数释放完了之后,delete才会去释放该对象,原理和new调用operator new是一样的,本质就是去调用free函数和malloc函数。
并且此时除了operator new和operator delete 还有一个operator new[];
一个原理,此时的调用原则就是:operator nwe[ ]->operator new->malloc
new和delete对于内置类型和自定义类型的区别
好的,搞懂了这些,此时我们就来看一下new和delete对于内置类型和自定义类型的区别,主要就是为了研究一下怎么写代码才不会出问题,到底需不需配套使用,例如:此时我有一个栈,我用这个栈在main函数中创建了一个局部对象 st(Stack st)
,此时的这个对象是因为它是一个自定义类型,所以此时它是不需要我自己去释放的,因为自定义类型都会去自己调用构造函数和析构函数,只有内置类型才是因为栈帧的销毁而销毁的,但一定要去注意指针这个内置类型, 因为指针变量都是一个内置类型的变量,无论是什么类型的指针都是一样的,例如:Stack* ptr和int* p1
,此时的ptr和p1在本质上都是一个内置类型对象,所以不需要我们自己去销毁,它会自己随着栈帧的销毁而销毁,明白了这个东西,此时重点就来了。
重点:虽然如上述所说,指针都是内置类型,会自己销毁,但是指针指向的那块空间是不会自己销毁的,所以此时如果你不仔细做处理的话,此时你的程序就会因为没有释放内存而崩溃,所以,当我们创建了一个指针变量的时候,就一定要考虑到,指针指向的空间存放在什么位置,例如:此时的该栈,栈中的数据中有一个数组,此时的该数组是一个动态数组,是通过new关键字开辟出来的,所以此时可以明显的知道,该空间是在堆区上的,所以此时ptr指针指向的该空间是不会自己释放的,所以需要我们进行手动释放,例如:(delete ptr;
),所以此时一个自定义类型的指针ptr,例如:Stack* ptr = new Stack;
此时就不可以像Stack* st;
一样,想要使用free和delete都可以释放指针指向的空间。因为Stack st;
并没有多余的空间需要清理,此时它只要把在栈中的成员变量中的那个指针,new开辟出来的那块动态数组的空间清理掉就可以了(因为该空间是栈中的new开辟出的一个动态数组),所以free
可以直接把st对象中的那块Stack
中的动态开辟的数组空间直接给释放掉。然而,我们的Stack* ptr = new Stack;
此时指针ptr是在内存中的栈帧上的,但ptr指向了一块new出来的Stack
,该Stack
是在堆区的,并且Stack中还有一个指针,该指针指向的空间又是new出来的,所以此时这块空间也是在堆区上的,所以此时ptr指向的空间又指向了一块空间,所以此时不可以直接free(ptr),
会有内存泄露问题,只有把Stack中new出来的空间给先释放才可以把ptr指向的空间释放,所以此时就不可以使用free去直接释放,而是要使用delete ptr;
去释放,因为delete会先去调用析构函数(但是前提是该指针指向的空间的类型为自定义类型),把ptr指针指向的空间中又开辟的空间给先析构掉,然后再去operator delete,调用free,去释放ptr指针指向的空间,但如果上述的情况你写成free ptr;也是可以的,只是少调用了一次析构函数而已,然后造成内存泄露的问题,因为在C和C++中并不会帮助我们检查内存泄露问题,所以综上,我们在释放内存的时候,一定要匹配使用,并且并不是自定义类型就一定有问题,主要是还要看该自定义类型中是否存在指针指向的另一块空间。
浅浅的摸一下泛型编程
从模板看泛型编程
写了这么久的代码,我们知道在C++中有一个东西叫函数重载,可以让我们把一个函数名(Swap)给重复使用,通过参数类型的不同来区别函数的不同,但是会发现,有一种类型的参数,我就需要写一个该类型的Swap函数,这样是比较麻烦的,所以C++中就又提出了模板的概念,该概念的意思就是可以让我们实现一个与类型无关的Swap函数,别的函数就通过该模板进行使用,就是相当于存在一个模具,通过给这个模具填充不同的材料(类型),来获得不同的铸件(既生成具体类型的代码),这样就可以节省很多的代码量了,所以总的来说:泛型编程就是编写与类型无关的通用代码,是代码复用的一种手段,模板就是泛型编程的基础。
什么是模板
首先模板分成两类,一个是函数模板,一个是模板类:
函数模板 |
---|
类模板 |
什么是函数模板
概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
具体模板的实现:如图
注意:此时虽然在调试期间,我们看到的是同一个函数,但是只是编译器处理过之后的,本质在系统内部,是两个不同的函数,从栈帧的大小和汇编代码这些方面都是可以看出来的。
并且此时我们知道在C++类和对象中,有一个对象实例化的过程,所以此时模板的使用也是有一个模板实例化的过程的,此时的该过程的理解,就可以让我们更好的理解为什么模板使用的是两个不同的函数,如图:
模板实例化的一些小问题:
主要是分为自动推演模板类型和显示实例化两种
什么是自动推演模板类型:例, cout << Add((double)b, d) << endl;cout << Add(a, (int)c) << endl;
此时就是我们自己去进行强制类型转换,把不是同类型的两个数据给转换成同一类型,这样才可以去实现模板,不会出现无法识别模板的问题,
显示实例化: cout << Add<double>(a, c) << endl; cout << Add<int>(b, d) << endl;
这两句代码就是显示实例化,直接把该数据的类型写在函数名的后面,确定了该函数数据的类型,此时这样模板就可以很好的识别参数了。
如图:
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;swap(a, b);swap(c, d);//实参传递给形参,自动推演模板类型cout << Add((double)b, d) << endl;cout << Add(a, (int)c) << endl;//显示实例化cout << Add<double>(a, c) << endl;cout << Add<int>(b, d) << endl;return 0;
}
并且此时强调,我们的库中已经用模板给我们实现了一个swap
函数,所以以后我们可以直接使用。
并且对于非模板函数和同名函数模板,如果其它条件都相同,在调用时会优先调用非模板函数而不会从该模板产生出一个实例,如果模板可以产生一个具有更好匹配的函数,那么选择模板(如类型不相同的两个数据);并且模板函数是不允许自动类型转换的,只有普通函数才可以进行自动类型转换。
如图:
什么是类模板
使用模板类,直接就可以把我们以前使用的typedef的方法给淘汰掉了,模板类直接就可以搞定每个数据结构的类型,直接使用显示实例化的方式,把该数据结构的类型给确定,根本不需要去改什么typedef定义的类型,一个尖括号(<>) 直接搞定了,剩下的交给编译器去完成就行了。
如图:
强调:类模板只能使用显示实例化的方式去使用
总结:C++这块老腊肉我们又小小的啃了一口,所以继续加油吧!
相关文章:
Learning C++ No.8【内存管理】
引言: 北京时间:2023/2/12/18:04,昨天下午到达学校,摆烂到现在,该睡睡,该吃吃,该玩玩,在一顿操作之下,目前作息调整好了一些,在此记录,2月11&…...
『 MySQL篇 』:MySQL表的相关约束
基础篇 MySQL系列专栏(持续更新中 …)1『 MySQL篇 』:库操作、数据类型2『 MySQL篇 』:MySQL表的CURD操作3『 MySQL篇 』:MySQL表的相关约束文章目录 1 . 非空约束 (not null)2 . 唯一性约束(unique)3 . check约束4 . 默认约束(default)5 . 主…...
家政服务小程序实战教程10-分类展示
小程序一般底部菜单栏会有一个分类的功能,点击分类,以侧边栏导航的形式列出所有类目,点击某个类目可以做数据筛选,我们本篇就实现一下该功能 01 优化数据源 在我们家政服务小程序里,我们已经建立了类型和服务的数据源…...
一篇文章带你学会Ansible的安装及部署
目录 前言 一、什么是Ansible 二、Ansible的工作方式 三、Ansible的安装 四、构建Anisble清单 1、清单书写方式 2、清单查看 3、清单书写规则 4、主机规格的范围化操作 五、ansible命令指定清单的正则表达式 六、 Ansible配置文件参数详解 1、配置文件的分类与优先…...
opencv常用函数
1)读视频 img cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if vc.isOpened():ret, frame vc.read() else:ret False while ret:#此处省略具体的操作ret, frame vc.read() # 读下一帧 vc.release() 2)保存视频 def mk_video_writer(vc, path,frame_…...
Java集合框架常见面试题
1. 剖析面试最常见问题之 Java 集合框架 1.1. 集合概述 1.1.1. Java 集合概览1.1.2. 说说 List,Set,Map 三者的区别?1.1.3. 集合框架底层数据结构总结 1.1.3.1. List1.1.3.2. Set1.1.3.3. Map 1.1.4. 如何选用集合?1.1.5. 为什么要使用集合? 1.2. Colle…...
医用雾化器单片机方案设计
产品概述 雾化器是一款基于电路板的振荡信号被大功率三极管进行能量放大,传递给压电陶瓷片,当压电陶瓷片受电信号的激励,产生高频谐振,并使吸附在微孔膜上的液体结产生超声振荡,将液体的结构打散而产生自然飘逸的雾。不…...
python魔术方法(一)
所谓的魔术方法就是让用户客制化类的方法,常常是python中开头有两个下划线的方法。 __new__() new是创建一个类的过程 class A:def __new__(cls,x):print("__new__")return super().__new__(cls)由于new函数是建立了一个对象,所以必须返回一…...
IDEA配置部署tomcat详细步骤(maven web 和Javaweb)
目录 读者手册 一、概念与准备工作 (一)概念 (二)准备工作 (三)IDEA配置tomcat服务器(maven web项目演示) ( 四)Javaweb项目创建tomcat演示 读者手册 读…...
没有设置密码,每次打开RAR文件却都要输密码?
有小伙伴说遇到这种情况:用WinRAR软件压缩RAR文件后,再次打开时显示需要输入密码,但自己压缩文件时并没有设置密码,后续不管几次压缩文件都需要密码,这是怎么回事呢? 其实,这很可能是之前设置压…...
想要知道有哪些免费API接口,看它就够了
免费API它来啦! 微信开放平台 https://open.weixin.qq.com/ 让你的应用支持微信登录、微信分享、微信支付等功能。 百度地图开放平台 https://lbsyun.baidu.com/index.php?titlewebapi 百度地图Web服务API为开发者提供http/https接口,即开发者通过…...
【Java】二叉树
一、树形结构 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点: 有一个特殊…...
C++学习记录——구 模板初阶
文章目录1、泛型编程和函数模板1、函数模板的实例化2、模板参数的匹配原则2、类模板1、泛型编程和函数模板 泛型编程顾名思义,泛用性很高。之前C可以用重载来对付同名函数,但还是麻烦,有一个类型的变量就得写一个类型的函数。C对此创建了库这…...
筑基五层 —— 位运算看这篇就行了
目录 一.修炼必备 二. 位运算 二.移位运算符 三.位运算综合使用 恭喜你,成功突破至筑基五层!!! 一.修炼必备 1.入门必备:VS2019社区版,下载地址:Visual Studio 较旧的下载 - 2019、2017、201…...
windows安装proget实现nuget私有包部署
下载proget 官网 下载地址 免费下载 安装proget 下载完成之后双击安装 选择ProGet 默认选择即可 也可以指定数据库,SQL Server数据库 Server服务器名;Database数据库名;User Id用户名;Password密码 Serverlocalhost;DatabaseProGet2;User Idsa;Passwordxxxx…...
SpringBoot简单集成OpenFeign
问题 在SpringBoot中简单集成Feign,不想使用Rest Temple了。 步骤 Maven <properties><spring.cloud-version>2022.0.1</spring.cloud-version></properties> <dependencyManagement><dependencies><dependency><g…...
dfs(九)字符串的全排列
字符串的排列_牛客题霸_牛客网【牛客题霸】收集各企业高频校招笔面试题目,配有官方题解,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力https://www.nowcoder.com/practice/fe6b651b66ae47d7ac…...
别具一格,原创唯美浪漫情人节表白专辑,(复制就可用)(html5,css3,svg)表白爱心代码(1)
别具一格,原创唯美浪漫情人节表白专辑, (复制就可用)(html5,css3,svg)表白爱心代码(1) 一、 前言 回眸之间,丰盈了岁月,涟漪了思绪,轻轻落笔,不写伤痕,不写仇怨,只写岁月…...
Hudi-集成Spark之spark-sql方式
Hudi集成Spark之spark-sql方式 启动spark-sql # 启动spark-sql之前需要先启动Hive的Metastore nohup hive --service metastore & #针对Spark 3.2 spark-sql \--conf spark.serializerorg.apache.spark.serializer.KryoSerializer \--conf spark.sql.catalog.spark_catal…...
快速排序基本原理
快速排序基本原理1.快速排序1.1 基本原理1.2 快速排序执行步骤1.2.1 分区包含步骤1.2.1 分区步骤1.3 快速排序大O记法表示2. 将[0,5,2,1,6,3]进行快速排序 【实战】2.1 第一次分区步骤2.2 第二次分区步骤2.3 第三次分区步骤2.4 第四次分区步骤3.快速排序代码实现1.快速排序 1.…...
Android开发笔记-提纲(连载中....)
文章目录Android概述Android开发学习笔记提纲1. 认识AS开发Android的基础入门知识2. 认识Activity的生命周期和基础使用3. 认识Activity之间的跳转和传值4. 认识Intent以及全局Activity的属性的共享5. 认识Service6. 学习跨应用服务【AIDL通信】Android概述 Android系统框架的四…...
React Native(一)
移动端触摸事件example1:<ButtononPress{() > {Alert.alert(你点击了按钮!);}}title"点我!" />Touchable 系列组件TouchableHighlight 此组件的背景会在用户手指按下时变暗TouchableNativeFeedback 会在用户手指按下时形成类似墨水涟…...
Kotlin 26. Kotlin 如何播放音频文件
Kotlin 如何播放音频文件 文章目录Kotlin 如何播放音频文件1 下载并放置音频文件2 activity_main.xml3 MainActivity.kt1 下载并放置音频文件 我们可以随便下载一个音频文件,比如 alarm.mp3,需要将其放置在 /res/raw/ 路径下。 2 activity_main.xml 这…...
recv和明文收包分析
我们CTRLg 跳到recv 分析收包函数 发现函数会断并且收包函数返回值(收包包长)也会不断变化 那么证明recv是真正的收包函数,游戏没有重新实现该函数 我们只要分析该函数即可 在recv函数执行完毕以后下断 eax是包长,esi28是包指针 我们上2个号,让另外…...
【IVIF的超分重建】
Multimodal super-resolution reconstruction of infrared and visible images via deep learning (基于深度学习的红外和可见光图像多模态超分辨率重建) 提出了一种基于编解码器结构的红外-可见光图像融合方法。图像融合任务被重新表述为保持红外-可见…...
“深度学习”学习日记。--加深网络
2023.2.13 深度学习 是加深了层的深度神经网络的学习过程。基于之前介绍的网络,只需要通过 叠加层, 就可以创建深度网络 之前的学习,已经学习到了很多东西,比如构成神经网络的各种层、参数优化方法、误差反向传播法,…...
2023前端面试总结含参考答案
文章目录1. 父子组件生命周期的执行顺序:2. 原型链:3. promise的理解:4. 数组循环,foreach,filter,map,reduce5. 数组去重,set6. 组件通信方式7. 路由钩子8. 首页首屏加载优化:9. th…...
总览 Java 容器--集合框架的体系结构
前言 我们在讲 Java 的数据类型的时候,单独介绍过数组,数组也确实是开发程序中常用的内存类型之一,不过 Java 内置的数组限制颇多,所以此后扩展出了List这种结构,与之类似的Set、Queue 这些内存中的容器都被放在了 Co…...
即便考分很好也不予录取的研究生复试红线,都是原则性问题
在浙大研究生招生录取政策文件中有这么一句话:坚持“按需招生、全面衡量、择优录取、宁缺毋滥”的原则,以提高人才选拔质量为核心,在确保安全性、公平性和科学性的基础上,做到统筹兼顾、精准施策、严格管理。字字体现出研究生招生…...
Android java创建子线程的几种方法
1.新建一个类继承自Thread,并重写run()方法,并在里面编写耗时逻辑。 1 2 3 4 5 6 7 class ThreadTest extends Thread { Override public void run() { //具体的耗时逻辑代码 } } new ThreadTest().st…...
武汉网站建设哪家好/网络推广软件有哪些
根据规划, 调试OsgEarth源码每周1800行源码抄写。 目前鬼火引擎8377行。正好从8月22日开始,到9月底,5周完成。 即:分配到周,应该达到下面的目标。 8月29日时,剩6577行(实际6438行,完…...
艺术设计教学资源网站建设标准/世界球队最新排名
一、处理JSON 1、将JavaScript数据转换为JSON对象(序列化) JSON.stringify(Object)2、将JSON数据转换为JavaScript对象(逆序列化) JSON.parse(stringJSON)二、Buffer模块缓冲数据(使用两位16进制表示一字节) 1、创建缓冲区 Buffer.from(array): returns …...
和创客贴类似的网站/怎么优化推广自己的网站
文档提要:大数据通常包含三大属性:数量、速度和种类。这些属性给传统的基于磁盘的关系型数据库带来了巨大挑战。不同类型的数据对存储功能和性能有着不同的要求,对应的成本也不同。SAP HANA平台提供了多种数据存储器和处理引擎。现在…...
建设厅官方网站新资质标准/百度网络推广怎么收费
关键词: Visio Studio2010 WinForm Sqlserver2008 ReportingService 报表身份验证问题分析:Sqlserver2008自带的Reporting Service报表提供了功能强大,多种样式可供选择的报表服务;利用它自己的Reporting站点,我们可以…...
网站建设初期目标/关键词优化排名软件
来于:http://segmentfault.com/q/1010000000422506 没有缓冲区时,每次读取操作都会导致一次文件读取操作(就是告诉操作系统内核我要读这个文件的这个部分,麻烦你帮我把它取过来)。有缓冲区时,会一次性读取…...
微信代运营公司/seo网站推广优化
如果您正在 寻找 一些很酷 的 下拉菜单解决 方案 , 那么这些要 。今天 , 我收集了 一些有用的 CSS和jQuery 下拉菜单 解决 方案 。Creating a pure CSS dropdown menuSexy Drop Down Menu w/ jQuery & CSSSliding Jquery MenuPerfect Dropdown Login…...