Cpp学习——动态内存管理

news2024/9/20 20:44:05

 

目录

一,new

1.malloc,realloc,calloc的使用不便之处

2.new的好处

3.opreator new

二,delete

1.为什么要有delete?

2.为什么要匹配使用?


一,new

1.malloc,realloc,calloc的使用不便之处

     在C语言中,为了申请堆上的空间我们便有了malloc ,realloc,calloc三个函数。malloc函数是最基本的动态内存申请函数。realloc在第一个指针型参数为NULL时是和malloc一样的,但是在第一个参数不为NULL时realloc函数开辟空间的方式有两种:1.原地扩容,2.异地扩容。

calloc函数与malloc函数开辟空间的方式都是一样的,但是calloc函数在开辟int*类型的空间时会有将空间内的数据初始化为0的行为。

     但是不管如何,这三个函数的使用方法都是差不多的。而且还有点麻烦:

1.因为这三个函数在使用时返回的都是void*类型的数据,所以在使用这三个函数开辟内存时都要有强转的操作。

2.使用时要计算类型的大小。

3.不能随意初始化。

2.new的好处

为了搞定上面的问题,祖师爷便搞出了new这个操作符。记住,new是一个操作符。new该怎么用呢?

1.new一个对象:new+类型。

2.如果要初始化:new+类型+(要初始化的值)。

3.new多个对象:new+类型+[个数]。

4.初始化多个对象:new +类型+[个数]+{初始化的值1,初始化的值2,……},若是整型则未被初始化的剩余空间的数据被初始化为0。

如:


	
	int* p1 = new int;
	cout << "p1:"<<p1 << endl;

	int* p2 = new int(10);
	cout << "p2:" << *p2 << endl;

	int* p3 = new int[6];
	cout << "p3:" << p3 << endl;


	int* p4 = new int[6]{ 1,2,3,4,5 };
	cout << "p4:";
	for (int i = 0;i < 6;i++)
	{
		cout << p4[i] << " ";
	}
	cout << endl;

结果:

 但是new的好处其实主要体现在对自定义类型的空间开辟上,比如说以前定义的栈。如果用malloc开辟空间并初始化的话就是这样的:

class Stack {
public:

	Stack()
	{
		cout << "Stack" << endl;
	}
	Stack(Stack& stack)
	{

	}

	~Stack()
	{
		cout << "~Stack" << endl;
	}

	void Init(int size = 4)
	{
		_arr = nullptr;
		_top = 0;
		_size = 0;
	}


private:
	int* _arr;
	int _top;
	int _size;
};


int main()
{
	Stack* st = (Stack*)malloc(sizeof(Stack));
	st->Init();
	return 0;

}

为了初始化那就得多写一个初始化函数。但是用new该怎么写呢?用new的话就不用再多写一个init初始化函数了,直接在构造函数里初始化便可以了。这也是用new开辟一个自定义类型的对象的特点——对自动调用构造函数初始化象。用new申请空间代码如下

class Stack
{
public:
	Stack()
	{
		_arr = (int*)malloc(sizeof(Stack)*4);
		_top = 0;
		_size = 0;
	}

	Stack(Stack& st)
	{

	}

	~Stack()
	{

	}


private:
	int* _arr;
	int _top;
	int _size ;
};
int main()
{
	//Stack* st = (Stack*)malloc(sizeof(Stack));
	//st->Init();
	Stack* st = new Stack;
	return 0;

}

这样就比malloc函数申请空间的做法简洁多了。总结一下,使用new的最方便的一点就是在申请一个类对象时能够自动调用构造函数初始化,从而不用我们来重新写一个初始化函数来初始化。

3.opreator new

operator new可不是一个函数重载。这个operator new其实可以理解为一个封装。什么的封装呢?其实就是malloc与try……catch的封装。这个operator new 其实也就是new这个操作符实现的一个关键的组成部分。进一步说new其实就是operator new和构造函数的封装。现在可以来看看new的底层:

 

operator new的底层:

这东西我暂时还讲解不清,了解一下operator new便可以了。 

二,delete

和new一样delete是Cpp中定义的一个操作符。这个操作符便是和new配合着使用的。和free一样,这个操作符是可以用来释放空间的防止内存泄漏的。delete的用法如下:

1.delete+变量:释放一个申请的一个变量的大小。

2.delete+[ ]:释放申请的多个空间的大小。

在这里一定要注意的是要匹配使用,不然会发生错误的。

1.为什么要有delete?

其实这里的原因和new一样,delete出现的最大价值是针对于自定义类型的。delete也可以看作是free+析构函数的封装。再剖析一下,其实delete就是operator delete+析构函数的封装,其实就是try……catch+free+析构函数的封装。因为delete能够调用析构函数,所以delete便可以很好的释放自定义类型的空间。

2.为什么要匹配使用?

其实对于一般的类型其实不匹配使用也没多大问题(会有内存泄漏但是不报错),但是对于有析构函数的自定义类型不匹配使用便会报错。如对有析构函数的栈:

class Stack
{
public:
	Stack()
	{
		_arr = (int*)malloc(sizeof(Stack)*4);
		_top = 0;
		_size = 0;
	}

	Stack(Stack& st)
	{

	}

	~Stack()
	{
       cout<<"~Stack"<<endl;
	}


private:
	int* _arr;
	int _top;
	int _size ;
};

int main()
{
	Stack* p = new Stack[10];
	delete p;//没有匹配调用delete
    return 0;
}

就会出错:

匹配调用后:

 

便是可运行的。

但是,在我屏蔽掉析构函数后再不匹配调用:

便又是可运行的了(有内存泄露问题)。这到底是为什么呢? 解答如下:

其实这就是因为释放内存空间的位置不对。假如我new出来的对象是n个有析构函数的对象,那Cpp底层就会在原来的地址伤向前偏移四个字节用来存放n这个整型。

 

 即使开多了四个字节的空间,但是我的p还是在原来的位置上。此时用delete与delete[ ]就决定了我是否要向前偏移四个字节。若用delete[ ]就会向前偏移四个字节取到前面四个字节储存的数据再释放,这样释放的位置便是对的便可以正常运行。但是用的是delete就不会发生偏移,释放的位置错了便会报错程序便会运行不下去。            

 但是,假如我new出来的对象是没有析构函数的话就不会在p的前面申请四个字节的空间。此时释放的话虽然有内存泄漏的问题但是却不会因为报错而运行不下去。总结一句,就是释放内存的位置不对。

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

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

相关文章

深度学习(33)——CycleGAN(2)

深度学习&#xff08;33&#xff09;——CycleGAN&#xff08;2&#xff09; 完整项目在在这里&#xff1a;欢迎造访 文章目录 深度学习&#xff08;33&#xff09;——CycleGAN&#xff08;2&#xff09;1. Generator2. Discriminator3. fake pool4. loss定义5. 模型参数量6…

无涯教程-Lua - 调试语句

Lua提供了一个调试库&#xff0c;该库提供了所有原始函数供无涯教程创建自己的调试器。即使没有内置的Lua调试器&#xff0c;也有许多针对Lua的调试器&#xff0c;这些调试器由各种开发人员创建&#xff0c;其中许多开源。 下表列出了Lua调试库中可用的函数及其用法。 Sr.No.…

【Spring Boot】请求参数传json对象,后端采用(map)CRUD案例(101)

请求参数传json对象&#xff0c;后端采用&#xff08;map&#xff09;接受的前提条件&#xff1a; 1.Spring Boot 的控制层接受参数采用&#xff1a;RequestBody 2.需要一个Json工具类&#xff0c;将json数据转成Map&#xff1b; 工具类&#xff1a;Json转Map import com.bao…

【MyBatis】MyBatis把空字符串转换成0的问题处理方案(96)

先看问题: Postman入参: MyBatis采用map循环插入: // Mapper接口层void addPar(Param(value "question") Map<String, Object> paramMap);<!-- 新增&#xff1a;参数 --><insert id"addPar" parameterType"map">INSERT IGNO…

DispatcherServlet、拦截器、处理器详解(通俗易懂)

DispatcherServlet、拦截器、处理器详解(通俗易懂) 1.DispatcherServlet ​ 想象一下你去一个大型办公楼寻找特定的办公室。你到达大厅&#xff0c;遇到一个接待员&#xff08;DispatcherServlet&#xff09;。你告诉接待员你要找的办公室&#xff08;请求的URL&#xff09;&…

iOS——Block循环引用

Capturing ‘self’ strongly in this block is likely to lead to a retain cycle 典型的循环引用 self持有了blockblock持有了self(self.name) 这样就形成了self -> block -> self的循环引用 解决办法 强弱共舞 使用 中介者模式 __weak typeof(self) weakSelf sel…

策略模式:优雅地实现可扩展的设计

策略模式&#xff1a;优雅地实现可扩展的设计 摘要&#xff1a; 策略模式是一种常用的设计模式&#xff0c;它可以帮助我们实现可扩展的、灵活的代码结构。本文将通过一个计算器案例来介绍策略模式的概念、使用场景以及如何在实际项目中应用策略模式来提高代码的可维护性和可扩…

海外ASO优化之如何探索竞争对手

查找有关竞争对手应用程序的所有有用信息&#xff0c;并对其进行分析&#xff0c;从而获得有效的见解。 发现与我们应用程序相关的关键词。将他们添加到竞争对手列表中&#xff0c;并通过关键词浏览器工具分析他们的表现。 1、调查竞争对手的 ASO 策略。 搜索查询研究所有国家…

【nginx】源码安装nginx以及手动配置域名ssl证书

安装nginx 下载地址:nginx: download 稳定版 上传源码包到linux目录&#xff0c;如/opt/nginx 安装nginx编译时需要的依赖 yum install -y pcre-devel zlib-devel openssl-devel wget gcc tree vim 编译安装nginx 解压nginx源码安装包&#xff0c;并进入解压后的目录&#…

maven打包时跳过测试

1、命令行 mvn clean install -DskipTests mvn clean -DskipTeststrue install 2、idea跳过 打包时通过idea先进行clean&#xff0c;在进行install&#xff0c;会自动跳过test

机器学习04-数据理解之数据可视化-(基于Pima数据集)

什么是数据可视化? 数据可视化是指通过图表、图形、地图等视觉元素将数据呈现出来的过程。它是将抽象的、复杂的数据转化为直观、易于理解的视觉表达的一种方法。数据可视化的目的是帮助人们更好地理解数据&#xff0c;从中发现模式、趋势、关联和异常&#xff0c;从而作出更明…

案例|会展大数据服务系统 智能服务体系建设实践

根据相关的市场调查发现在国内进行的2000多个会展项目中&#xff0c;仅有15%的项目能够提供相关主题网站基本业务和服务&#xff0c;且提供的服务并不能够满足会展各方的应用&#xff0c;剩余的大部门会展项目信息系统构建的不够完善、技术性差、应用复杂等&#xff0c;甚至提供…

python_在K线找出波段_02_找出波段

承接 【python_在K线找出波段_01_找出所有转折点】博文 地址&#xff1a;python_在K线找出波段_01_找出所有转折点_程序猿与金融与科技的博客-CSDN博客 目录 写在前面&#xff1a; 寻找波段的逻辑&#xff1a; 寻找方法 判断高低点连线是否有效 判断方法: 判断点相对连…

画图干货!14种uml图类型及示例

1. 什么是 UML UML 是统一建模语言的缩写。UML 图是基于 UML&#xff08;统一建模语言&#xff09;的图表&#xff0c;目的是直观地表示系统及其主要参与者、角色、动作、工件或类&#xff0c;以便更好地理解、更改、维护或记录信息关于系统。简而言之&#xff0c;UML 是一种…

项目经理必备-项目总体计划模板-制式文件,可直接填写使用-公司可用

合同中完整项目名称&#xff0c;黑体&#xff0c;28号字&#xff0c; 居中对齐&#xff0c;项目名称较长时换行填写 当前文档名称&#xff0c;黑体&#xff0c;小初&#xff0c; 居中对齐&#xff0c;文档名称较长时 换行填写 版 本 号 x.x 编制人 日期 20xx年xx月xx日…

【css】css实现一个简单的按钮

四种链接状态分别是&#xff1a; a:link - 正常的&#xff0c;未访问的链接a:visited - 用户访问过的链接a:hover - 用户将鼠标悬停在链接上时a:active - 链接被点击时 <style> a:link, a:visited {//未访问、访问过background-color: #07c160;//设置背景颜色color: wh…

吉客云·奇门对接打通金蝶云星空销售单查询接口与销售出库新增接口

吉客云奇门对接打通金蝶云星空销售单查询接口与销售出库新增接口 对接系统&#xff1a;吉客云奇门 “吉客云”是一站式企业数字化解决方案系统&#xff0c;可实现业务、财务、办公、人事等一体化管理。相对于传统多套软件系统的集成方案&#xff0c;“吉客云”具有业务流程更流…

Vue3描述列表(Descriptions)

&#x1f601; 整体功能效果与 ant design vue 保持高度一致 &#x1f601; 包含两种组件&#xff1a;Descriptions 和 DescriptionsItem&#xff08;必须搭配使用&#xff01;&#xff09; APIs Descriptions 参数说明类型默认值必传title描述列表的标题&#xff0c;显示在…

Dos 命令简介

DOS 简介 DOS是Disk Operating System的缩写&#xff0c;即“磁盘操作系统”。DOS主要是一种面向磁盘的系统软件&#xff0c;有了DOS&#xff0c;我们就可以更容易理解怎么给机器下命令&#xff0c;不必去深入了解机器的硬件结构&#xff0c;也不必去死记硬背那些枯燥2进制数字…

图论-简明导读

计算机图论是计算机科学中的一个重要分支&#xff0c;它主要研究图的性质和结构&#xff0c;以及如何在计算机上有效地存储、处理和操作这些图。本文将总结计算机图论的核心知识点。 一、基本概念 计算机图论中的基本概念包括图、节点、边等。图是由节点和边构成的数据结构&am…