C++动态内存区域划分、new、delete关键字、泛型编程、函数模版、类模版

news2024/12/23 18:58:17

目录

一、C/C++中程序的内存区域划分

为什么会存在内存区域划分?

二、new关键字

1、内置类型的new/delete使用方法:

2、new和delete的本质

3、常见面试题——malloc/free和new/delete的区别

三、模版

1、泛型编程

2、函数模版

(1)、引言

(2)、概念

3、模版原理

4、模版的实例化

5、类模版

6、匹配调用规则:

7、类模板注意事项:


一、C/C++中程序的内存区域划分

为什么会存在内存区域划分?

因为不同数据有不同的存储需求,各区域满足不同的需求。

例如:

(1)、一些临时变量,局部变量存储在栈区

(2)、常用数据结构或一些算法(如归并排序)中会用到动态内存开辟,该内存是在堆区申请。

(3)、全局变量、静态变量存储在数据段(静态区)。

(4)、一些只读数据,如字符常量、可执行代码(指令)存储在代码段(常量区)。

二、new关键字

 C语言中动态内存管理方式使用malloc/calloc/realloc/free函数来实现,C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过newdelete操作符进行动态内存管理。

1、内置类型的new/delete使用方法:

	//动态申请一个int型
	int* a = new int;

	//动态申请一个int型,并初始化为10
	int* a1 = new int(10);

	//动态申请一个int型数组
	int* arr1 = new int[10];
	
	//动态申请一个int型数组,并初始化
	int* arr2 = new int[3] {1, 2, 3};

	//若为完全初始化,则后面的值会默认初始化为0
	int* arr3 = new int[10] {1, 2, 3};

	//每new一个变量,用完后一定要delete
	delete a;
	delete a1;
	//注意数组的区别
	delete[] arr1;
	delete[] arr2;
	delete[] arr3;

注意:使用new未初始化时,不会有默认值,而是随机值。

2、new和delete的本质

new的本质是为了解决动态申请的自定义类型对象的初始化问题。

因为C语言中malloc函数不能给自定义类型进行初始化:

	//malloc不能给自定义类型初始化
	A* p1 = (A*)malloc(sizeof(A));

所以这时就可以用new和delete:

(1)、new的本质:开空间+调用构造函数初始化;

(2)、delete的本质:先调用析构函数+释放空间。

如下:

	//new给自定义类型初始化
	//调用默认构造函数
	A* p2 = new A();
	//调用带参数构造函数
	A* p3 = new A(1);

	//给对象数组初始化
	//(1)、有名对象
	A aa1, aa2, aa3;
	A* arr1 = new A[3]{ aa1,aa2,aa3 };
	//(2)、匿名对象
	A* arr2 = new A[3]{ A(),A(),A()};
	//(3)、隐式类型转换
	A* arr3 = new A[3]{ 1,2,3 };

注意:

(1)、内置类型的底下申请释放,new和malloc除了用法上,没有区别;

(2)、malloc申请失败会返回NULL,而new申请失败会抛异常;

3、常见面试题——malloc/free和new/delete的区别

从用法+原理角度区分:

malloc/freenew/delete
共同点是:都是从堆上申请空间,并且需要用户手动释放。
不同点是:
1. mallocfree是函数,newdelete是操作符
2. malloc申请的空间不会初始化,new可以初始化
3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可
4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new 要捕获异常
6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new 在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成 空间中资源的清理。

三、模版

1、泛型编程

泛型编程通俗来讲就是写跟具体类型无关的代码,广泛的编程。是代码复用的一种手段。模板是泛型编程的基础。

2、函数模版

(1)、引言

我们以交换函数为例,看下列代码:

void Swap(int& p1, int& p2)
{
	int tmp = p1;
	p1 = p2;
	p2 = p1;
}

void Swap(char& p1, char& p2)
{
	char tmp = p1;
	p1 = p2;
	p2 = p1;
}

void Swap(double& p1, double& p2)
{
	double tmp = p1;
	p1 = p2;
	p2 = p1;
}

这是用函数重载的知识,但函数重载也有不好的地方:

1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数。
2. 代码的可维护性比较低,一个出错可能所有的重载均出错。
正如上述各函数,我们发现好像只有类型不同,这时我们就可以用模版来减少代码的冗余。
(2)、概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
格式:
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
例如上述代码,我们可以写成:
template<typename T>

void Swap(T& p1, T& p2)
{
	T tmp = p1;
	p1 = p2;
	p2 = tmp;
}

当有多种类型时,就可以写多个typename(或class):

注意:

typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

3、模版原理

注意一点:
模版处只有一个函数,为什么会是调用的两个函数?这就是模版的原理所造成的现象:
原理:
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供 调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然 后产生一份专门处理double类型的代码,对于字符类型也是如此。

4、模版的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
模版参数语法很类似函数参数,只是函数参数定义的是形参对象,而模版定义的是类型。

(1)、推演实例化:例如上述内容,是编译器自己识别模版是什么类型,就叫推演实例化。

(2)、显示实例化:

//单类型模版显示调用
Swap<int>(1, 1);
//多类型模版显示调用
Test<int, double>(1, 5.5);

有一些情况只能用显示实例化,比如无参函数,传不了参数,就不能靠推演确定类型,这时只能显示实例化模版:

5、类模版

(1)、类模版定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};

特别注意:类模版必须显示实例化:

然后模版与类之间不能存在函数使用模版,同理想要函数模版,中间也不能穿插类使用模版。

6、匹配调用规则:

1、有现成的函数可以匹配就调用现成。

2、有合适的就调用合适的,没有就将就。

7、类模板注意事项:

(1)、使用类模版后,当成员函数的声明与定义分开写时,会有改变:

template<class T>
class Test
{
public:
	//构造函数
	//声明
	Test(T i);
private:
	int _i;
};

//定义
template<class T>
Test<T>::Test(T i)
{
	T tmp;
}

(2)、特别注意:

普通类:类名就是类型。

类模板实例化的类:类名不是类型,类名<数据类型>才是整个类的类型。

也就是说:显示实例化类模板的类型不同,它们就是不同的类:

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

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

相关文章

ASP.NET在线毕业论文提交系统的设计与实现

摘 要 本设计就很好的解决了上面的问题&#xff0c;它不但能实现毕业生论文的在线提交&#xff1b;还能给教师一定的权限&#xff0c;以在线的方式对自己指导的学生的论文进行审核&#xff1b;并且管理员还可以方便的将每个学生的论文信息按统一的论文排版本格式导出成word文…

大模型LLM 结合联网搜索增强isou

参考&#xff1a; https://github.com/yokingma/search_with_ai 在线使用网址&#xff1a; https://isou.chat/ 安装github下载&#xff0c;运行docker compose 如果一直报下面错误&#xff1a; 解决方法https://github.com/yokingma/search_with_ai/pull/7 默认打开&a…

阿里云VOD视频点播流程(2)

二、视频点播 1、入门代码 基于OSS原生SDK上传 &#xff0c;参考文档&#xff1a;https://help.aliyun.com/zh/vod/user-guide/upload-media-files-by-using-oss-sdks?spma2c4g.11186623.0.0.1f02273fj4lxNJ 视频点播面向开发者提供了丰富的上传方式&#xff0c;其中上传SDK&…

浅谈内存泄漏

内存泄漏 概念 在JavaScript中&#xff0c;内存泄漏是指应用程序在不再需要使用某块内存时仍然保持对其的引用&#xff0c;导致内存不能被垃圾回收机制释放&#xff0c;最终导致内存占用过高&#xff0c;性能下降。 内存泄漏通常发生在以下情况&#xff1a; 全局变量&#…

函数递归练习

目录 1.分析下面选择题 2.实现求第n个斐波那契数 3.编写一个函数实现n的k次方&#xff0c;使用递归实现。 4.写一个递归函数DigitSum(n)&#xff0c;输入一个非负整数&#xff0c;返回组成它的数字之和 5.递归方式实现打印一个整数的每一位 6.实现求n的阶乘 1.分析下面选择…

linux Docker在线/离线服务安装并支持centos7和centos8系统

注&#xff1a;以下内容都是经过测试;能在生产环境使用. 一、centos7版本的docker在线安装 1&#xff1a;运行以下命令&#xff0c;下载docker-ce的yum源。 sudo wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo…

外卖系统拦截器实现(Interceptor)

SpringMVC的拦截器主要是用于拦截控制器方法的执行&#xff1b; 概念&#xff1a;是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。在Spring中动态拦截控制器中方法的执行。 作用&#xff1a;在指定的控制器中调用前后执行预先设定的代码&#xff0c;完成功能增强。 应…

人才测评:计划管理能力与岗位胜任力素质测评

计划管理能力指的是什么&#xff1f; 计划管理能力&#xff0c;可以体现为从业者在精准制定好任务&#xff0c;或是根据任务的时间长&#xff0c;困难的程度来设定好完成的目标&#xff0c;一步一个脚印将工作完成好&#xff0c;并且能预估出可能出现的突发事件&#xff0c;将…

STM32--HC-SR501 热释电人体红外感应模块

实物引脚图&#xff1a; 模块工作特性&#xff1a; 当人进入感应范围之后输出引脚输出高电平&#xff0c;人离开感应范围自动延时输出低电平 热释电效应&#xff1a; 热释电传感器&#xff0c;也称为人体红外传感器&#xff0c;其工作原理基于热释电效应。这种传感器由几个关…

2024护网在即,今年的护网招聘着实有点离谱了!

最近刷到条护网招聘的朋友圈&#xff0c;今年的护网待遇着实有点离谱了&#xff0c;日薪提到了1w&#xff0c;还是全款垫付&#xff1f;&#xff1f;&#xff1f;&#xff01;&#xff01; 我算是理解了“我们当年可没你现在这个条件”这句话。 先给大家科普下护网行动&#x…

【C语言】6.C语言VS实用调试技巧(2)

文章目录 6.调试举例17.调试举例28.调试举例3&#xff1a;数组9.编程常⻅错误归类9.1 编译型错误9.2 链接型错误9.3 运⾏时错误 – 6.调试举例1 求 1!2!3!4!…10! 的和。 int main() {int n 0;int i 0;int ret 1;int sum 0;for (n 1; n < 3; n) {for (i 1; i < …

数据结构之栈与队列

一.栈 1.定义&#xff1a;一种线性表&#xff0c;只允许在固定的一端进行删除和插入数据的操作&#xff0c;该端叫栈底&#xff0c;另一端叫栈顶 2.特点&#xff1a;先进后出 注&#xff1a;栈中元素出栈是一对多的(他虽然满足先进后出但是我们可以在pop数据前先获取栈顶元素…

Tower for Mac:Git管理的新境界

Tower for Mac&#xff0c;让您的Git管理进入新境界&#xff01;这款专为Mac用户打造的Git客户端&#xff0c;凭借其出色的性能和丰富的功能&#xff0c;成为众多开发者的首选工具。 Tower不仅支持常规的Git操作&#xff0c;如提交、推送和拉取&#xff0c;还提供了许多高级功能…

【微服务最全详解】

文章目录 微服务微服务的介绍微服务服务架构演变 微服务网关微服务的负载均衡微服务的容灾机制服务崩溃服务容灾机制微服务熔断机制微服务限流Sentinel怎么实现限流微服务限流算法1.令牌桶算法2.漏斗桶算法 服务监控日志收集 微服务 微服务的介绍 微服务是一种软件架构风格&a…

MyBatis的创建和测试

创建项目点击Spring Initializr然后点击next 点击SQL 选择里面的Mybatis Framework和Mysql Driver 按如下图片创建项目 user表中的数据 #下面这些内容是为了让MyBatis映射 #指定Mybatis的Mapper文件 mybatis.mapper-locationsclasspath:mappers/*xml #指定Mybatis的实体目录 my…

使用人人开源renren-fast快捷搭建后台管理系统

https://gitee.com/renrenio/renren-fast https://gitee.com/renrenio/renren-fast 初始化项目数据库 导入项目运行 期间遇到的坑 024-04-25 01:30:27.638 ERROR 25228 --- [ main] com.alibaba.druid.pool.DruidDataSource : init datasource error, url: jdbc:…

【安全每日一讲】API是什么?解密API背后的奥秘

什么是API? API全称Application Programming Interface&#xff0c;即应用程序编程接口&#xff0c;是一些预先定义的函数&#xff0c;或指软件系统不同组成部分衔接的约定&#xff0c;用于传输数据和指令&#xff0c;使应用程序之间可以集成和共享数据资源。 简单来说&#…

thinkphp8 framework和 element plus admin前后端分离系统之PHP安装教程

DIYGW-UI-PHP是一款基于thinkphp8 framework和 element plus admin开发而成的前后端分离系统。目的是结合现有diygw-ui打造一个后台API开发。 实现PHP源码前请先下载小皮面板或者宝塔。 系统已经集成了部分功能 用户管理 后台用户管理部门管理 配置公司的部门结构&#xff0…

用红黑树封装出map与set

目录 一、红黑树的改造 节点结构的定义 迭代器类的实现 红黑树中提供迭代器 红黑树的主要代码 二、set的实现 三、map的实现 四、测试代码 map与set的底层都是红黑树&#xff0c;所以本篇文章就分享如何用同一颗红黑树封装出map与set 所以大家可以先去看一下我的讲解红…

先有JVM还是先有垃圾回收器?很多人弄混淆了

是先有垃圾回收器再有JVM呢&#xff0c;还是先有JVM再有垃圾回收器呢&#xff1f;或者是先有垃圾回收再有JVM呢&#xff1f;历史上还真是垃圾回收更早面世&#xff0c;垃圾回收最早起源于1960年诞生的LISP语言&#xff0c;Java只是支持垃圾回收的其中一种。下面我们就来刨析刨析…