C++内存管理与模板

C++内存管理与模板

文章目录

  • C++内存管理与模板
    • 前言:
      • 一.new和delete基本用法
      • 二.底层实现
      • 三.定位new
      • 四.模板
        • 4.1函数模板
        • 4.2调用选择
        • 4.3类模板
        • 4.4声明定义分离

前言:

C++的内存管理和C语言中动态内存分配是相似的,在这一篇我们会学到更符合面向对象的new和delete;

学习模板知识,是我们迈入STL的最后一步,届时可以飞速转为C++选手;

一.new和delete基本用法

在这里插入图片描述

new后面加类型会开辟类型大小的空间,p1维护一个整型的空间,使用圆括号进行初始化;单纯用new在堆上开辟的空间使用delete释放。

parr维护一个5个double元素的数组,使用{}为数组按顺序初始化,未完全初始化的默认给0;使用new[]开辟空间的使用delete[]释放,具体原因后面讲。

以上对内置类型进行堆空间分配和释放和C语言使用malloc和free本质上没有区别,只是用法上不太一样,比如不需要计算类型大小、无需强转。

new和delete解决的问题不在于内置类型,而是自定义类型,请看下面代码:

在这里插入图片描述

在这里插入图片描述

new在为类对象开辟空间的时候,会调用类对象的构造函数初始化对象,这是为了符合“刚创建的对象最好一开始进行初始化”,因此new有两个功能:1.开辟空间;2.调用构造函数;

对于自定义类型会去调用构造函数,对于内置类型不会,因为没有构造函数可以掉,在C++中很多都是针对自定义类型的,这是面向对象的特征。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

delete在释放new为类对象开辟的空间之前会先调用析构函数进行资源清理,然后再释放对象,也就是说delete的功能是:1.清理资源;2.释放空间;

接下来我们讲一个复杂一点的:创建栈对象

class Stack
{
public:Stack(int capacity = 4){cout << "Stack(int capacity = 4)" << endl;_a = new int[capacity];//new开辟空间失败不返回空指针_top = 0;_capacity = capacity;}~Stack(){cout << "~Stack()" << endl;delete[] _a;_a = nullptr;_top = _capacity = 0;}private:int* _a;int _top;int _capacity;
};int main()
{Stack* ptr = new Stack;delete ptr;return 0;
}

在这里插入图片描述

到这里,new和delete使用我们讲清楚了,那么new和delete到底是什么呢?它是如何完成这些工作的,让我们来看看new和delete的底层。

二.底层实现

new和delete是C++里的两个操作符,基本用法就是上面讲的。在C语言中malloc是用来开辟空间的,但是如果失败返回空指针不符合C++面向对象的惯常做法,此时祖师爷封装了这么一对全局函数:

在这里插入图片描述

operator new的主逻辑是调用C库中的malloc函数,然后对malloc开辟空间失败的情况进行封装,从返回空指针变成更符合面向对象的抛异常。

因此读者可以这么理解:operator new本质就是一个封装版的malloc,对malloc开辟空间失败的情况做了处理。

讲到这里,相信大家已经猜到operator delete的本质是free了。没错,operator delete单纯是用来配对operator new,和free本质上没有区别。

读者:好,博主,我知道了!这是两个全局函数,那它和new、delete这两个操作符有什么关系呢?

在这里插入图片描述

当我们使用new这个操作符的时候,翻译成汇编看到:编译器会自动去调用operator new这个函数,还有调用构造函数的。delete也是,会先调用析构函数,再调用operator delete。

到这里,new和delete再也不是很神秘的东西了,底层的operator new 和 operator delete就是C语言中的malloc和free。

在这里插入图片描述

在这里插入图片描述

我们看到如果在使用new[]的时候,调用operator new[]这个函数,但是进到这个函数内部,立马调用operator new,因此这个带[]的new函数仅是为了对称。

开辟5个栈对象,总大小应该是60才对,为什么是64呢?

在这里插入图片描述

我们看ptr的指针是指向E67C的,E678是5,我们连蒙带猜的把这个整型空间算在ptr里的话就算是指向一块64字节大小的空间。

没错,实际上对于new[]的时候,会多开辟一个整型空间用来存储对象个数。用途是:用来给delete[]使用,这也是delete[]的[]里不需要写析构对象个数的原因。

那么到这里我们就能明白为什么new/delete、new[]/delete[]要搭配使用了,因为如果使用new[]和delete,此时delete并不像deletep[]一样会释放指针-4的位置,那么就会导致开辟的空间部分释放,运行报错!

同理,malloc/free与new/delete最好也不要混着使用,老老实实配套使用就不会坑自己。

三.定位new

int main()
{//以下这两句组合相当于: Stack* p1 = new Stack(10);//1.开辟空间Stack* p1 = (Stack*)operator new(sizeof(Stack));//2.调用构造  定位new:显示调用构造函数的方法new(p1)Stack(10);//以下两句组合等同于:delete p1;//3.清理资源 C++中可以显示调用析构函数p1->~Stack();//4.释放空间operator delete(p1);return 0;
}

在这里插入图片描述

定位new的使用是:new(指针)类型(初始化列表)这样,就可以显示调用构造函数了,在内存池技术中发挥用武之地。

在这里插入图片描述

在这里插入图片描述

以上就是C++中的内存管理学习,我们接着往下进入模板的学习!

四.模板

4.1函数模板

在生活中,处处有模板的身影,比如语文答题模板、活字印刷技术等等很多。模板的出现,让相似的问题得以快速的解决,在计算机中,也有模板的身影:

//这两个交换函数除了类型以外,没有任何不同
void Swap(int& left, int& right)
{int tmp = left;left = right;right = tmp;
}void Swap(double& left, double& right)
{double tmp = left;left = right;right = tmp;
}

对于这种只有类型不同,逻辑一样的函数需要写两个函数,祖师爷早就看不惯了:

//函数模板
template<typename T>
void Swap(T& left, T& right)
{//模板参数TT tmp = left;left = right;right = tmp;
}int main()
{int a = 10, b = 20;double c = 1.1, d = 2.2;Swap(a, b);Swap(c, d);return 0;
}

模板参数T指的是类型,使用tmplate<typename 类型名>类型名可以任意起,因为是定义类型的,博主的习惯是取为T(type)。那么这个模板有什么用?请看下面代码:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

从上图看出不管是int还是double调用,调试的时候都是进入函数模板,表面上看起来像走了模板函数一样。

但实际上Swap(a,b)的时候,函数模板通过实参的类型,编译器推断模板参数T是int,然后编译器生成了一份整型交换的Swap函数并调用,这就是函数模板的参数推演。

所以Swap(a,b)和Swap(c,d)调用的不是同一个函数(它们地址不同),是调用编译器确定的函数参数T照函数模板生成的那份函数代码。

在这里插入图片描述

可以使用多个模板参数,多个模板参数的定义和多个函数参数的的定义是一样的,typename和class可以互换,博主习惯使用class。举个例子就是下面的代码:

template<class T1, class T2>
4.2调用选择

在这里插入图片描述

当模板和现有的函数存在时,如果现有的函数是合适的,那么就不会调用编译器通过模板生成的,而是调用现成的。

在这里插入图片描述

在这里插入图片描述

没有现成的函数就让编译器通过模板生成一个,调用生成的函数。此外,如果没有函数模板,能通过隐式类型转换符合参数类型的现成函数可以凑合被调用。

在这里插入图片描述

在这里插入图片描述

以上就是编译器根据函数模板生成的与现成函数的调取情况,可能不同编译器的具体情况不太一样,博主使用的是VS2019。

前面编译器根据实参推演生成的函数都是被动的,我们可以主动给模板参数类型,让编译器生成对应的函数,下面请看显示实例化:

在这里插入图片描述

这种函数的参数与模板参数没有关系或者函数没有参数的,就不能通过传递实参让编译器根据实参的类型,推演生成对应类型的函数代码,而要程序员自己实例化。

以上是实例化的方式,也就是语法规则,记住就好了。

4.3类模板

类模板是用来对只有类型不同的代码简化方法,请看下面代码:

template<class T>
class Stack
{
public:Stack(int capacity = 4){_a = new T[capacity];_top = 0;_capacity = capacity;}~Stack(){delete[] _a;_a = nullptr;_top = 0;_capacity = 0;}
private:T* _a;int _top;int _capacity;
};int main()
{Stack<int> st1;//整型栈Stack<double> st2;//double类型栈return 0;
}

当我们定义了一个栈的类模板后,对于存储不同数据类型的栈不再需要写两份(只有数据类型不同)代码了,通过显示类模板实例化,让编译器为我们生成即可!

4.4声明定义分离
template<class T>
class Stack
{
public://Stack是类名,构造函数是和类名相同的Stack(int capacity = 4);~Stack(){delete[] _a;_a = nullptr;_top = 0;_capacity = 0;}
private:T* _a;int _top;int _capacity;
};//声明定义分离的时候,模板参数要跟上
template<class T>
Stack<T>::Stack(int capacity)
{_a = new T[capacity];_top = 0;_capacity = capacity;
}int main()
{//它们是同一个类模板实例化出来的栈,但不是同一个类型Stack<int> st1;//Stack<int>是一个类型 存放整型的栈Stack<double> st2;//Stack<double>是另一类型 存放double的栈return 0;
}

在这里插入图片描述

类模板中,声明和定义分离,定义指明类型(Stack<T>)这是因为模板参数T在成员函数中是有作用的,即使在某些成员函数中没有使用到T,也需要加上,不能单靠Stack::。

ok,以上就是C++中内存管理和模板的知识学习,希望读者读完有所收获。

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

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

相关文章

如何快速写出高效的软件测试用例

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前言 编写测试用例的目的就是确保测试过程全面高效、有据可查。但要编写出高效的测试用例&#…

鸿蒙harmony--TypeScript基础语法

把青春献给身后那座辉煌的都市&#xff0c;为了这个美梦我们付出着代价 目录 一&#xff0c;基础类型 二&#xff0c;数组 三&#xff0c;any 四&#xff0c;变量的类型注释 五&#xff0c;函数 5.1 参数类型注解 5.2 返回类型注解 5.3 匿名函数 六&#xff0c;对象类型 可选属…

APP攻防-资产收集篇反证书检验XP框架反代理VPN数据转发反模拟器

知识点 1、APP资产-抓包突破&反模拟器 2、APP资产-抓包突破&反证书检验 3、APP资产-抓包突破&反代理VPN 章节点&#xff1a; 1、APP资产-内在提取&外在抓包 2、APP逆向-反编译&删验证&重打包 3、APP安全-存储&服务&组件&注册等 专题点&…

HDFS HA 之 HA 原理

1 ZKFC解析 HA(High Availability)是HDFS支持的一个重要特性,可以有效解决Active Namenode遇到故障时,将可用的Standby节点变成新的Active状态的问题,使集群能够正常工作。目前支持冷切换和热切换两种方式。冷切换通过手动触发,缺点是不能够及时恢复集群。实际生产中以应用…

2024年【危险化学品经营单位主要负责人】报名考试及危险化学品经营单位主要负责人免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位主要负责人报名考试参考答案及危险化学品经营单位主要负责人考试试题解析是安全生产模拟考试一点通题库老师及危险化学品经营单位主要负责人操作证已考过的学员汇总&#xff0c;相对有效帮助危险化…

LeetCode:49. 字母异位词分组

49. 字母异位词分组 1&#xff09;题目2&#xff09;代码3&#xff09;结果 1&#xff09;题目 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs…

python爬虫3

1.异常处理&#xff0c;使代码更加健壮 静态cookie可视绕过登录的限制 快代理是一个代理平台 # https://movie.douban.com/j/chart/top_list?type5&interval_id100%3A90&action& # start0&limit20# https://movie.douban.com/j/chart/top_list?type5&int…

【数据结构】 归并排序超详解

1.基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。 将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff0c;即先使每个子序列有序…

Vue3的Props

Vue 3中的props是用于接收父组件传递的数据的属性。在Vue 3中&#xff0c;props的声明发生了一些改变&#xff1a; 使用props选项来声明props。之前的版本中使用props属性来声明&#xff0c;但在Vue 3中改为使用props选项。通过TypeScript或Flow来静态类型检查props。Vue 3允许…

Spring实现事务(一)

Spring事务 .什么是事务事务的操作Spring中事务的实现准备工作创建表创建项目,引入Spring Web, Mybatis, mysql等依赖配置文件实体类 编程式事务(手动写代码操作事务)声明式事务(利用注解自动开启和提交事务) . 什么是事务 事务是⼀组操作的集合, 是⼀个不可分割的操作 在我们…

国产校准件

国产校准件 Ceyear系列校准件是矢量网络分析仪的测试附件&#xff0c;可大幅提高矢量网络分析仪的测试精度。规格品种丰富&#xff0c;涵盖多种同轴、波导校准件&#xff0c;校准精度高&#xff0c;重复性好 功能特点 校准件 校准模块可实现更精准的测量&#xff0c;满足您的测…

RK3588平台开发系列讲解(视频篇)H.264码流结构介绍

文章目录 一、 码流查看工具二、 I帧、 P帧、 B帧三、序列四、GOP, 即关键帧间隔五、片和宏块沉淀、分享、成长,让自己和他人都能有所收获!😄 📢H.264码流结构介绍。 一、 码流查看工具 ① H.264码流查看工具: Elecard_streamEye、 Elecard StreamEye Tools、 Special…

020 switch多选择结构

什么是switch多选择结构 switch语句中的变量类型为char的示例 char grade A; switch (grade){case A:System.out.println("成绩为A");break;case B:System.out.println("成绩为B");break;case C:System.out.println("成绩为C");break;case D:S…

2. HarmonyOS应用开发DevEcoStudio准备-1

2. HarmonyOS应用开发DevEcoStudio准备-1 下载 DevEco Studio 进入HUAWEI DevEco Studio产品页产品页。 单击下载列表右侧的按钮&#xff0c;下载 DevEco Studio。 安装 DevEco Studio 下载完成后&#xff0c;双击下载的 deveco-studio-xxxx.exe&#xff0c;进入 DevEco St…

基于SSM的高校社团管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 我欲乘风归去 又恐琼楼玉宇 高处不胜寒 -苏轼 目录 一、项目简介 二、开发技术与环境配置 2.1 SSM框架 2.2 …

使用STM32的FMC/FSMC接口实现多路数据传输和并发操作的设计与应用

在基于STM32的系统中&#xff0c;FMC&#xff08;Flexible Memory Controller&#xff09;/FSMC&#xff08;Flexible Static Memory Controller&#xff09;接口可以用于实现多路数据传输和并发操作。通过合理的设计和应用&#xff0c;我们可以提高系统的数据处理速度和效率。…

P1228 地毯填补问题

地毯填补问题 题目描述 相传在一个古老的阿拉伯国家里&#xff0c;有一座宫殿。宫殿里有个四四方方的格子迷宫&#xff0c;国王选择驸马的方法非常特殊&#xff0c;也非常简单&#xff1a;公主就站在其中一个方格子上&#xff0c;只要谁能用地毯将除公主站立的地方外的所有地…

数据可视化 pycharts实现时间数据可视化

自用版 数据格式为&#xff1a; 运行效果为&#xff1a; from pyecharts import options as opts from pyecharts.charts import Polar, Page import csv filename "./hot-dog-places.csv" data_x [] data_y [] with open(filename) as f:reader csv.reade…

前端使用cache storage实现远程图片缓存

Cache Storage 的主要特点和用途 缓存网络资源&#xff1a;可以将经常访问的网络资源缓存到 Cache Storage 中&#xff0c;以提高网页加载速度&#xff0c;减少网络请求。离线访问&#xff1a;当用户处于离线状态时&#xff0c;可以使用 Cache Storage 中的缓存资源来加载网页…

【系统设计】12306架构设计难点(下)

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…