Cpp学习——动态内存管理

2023-11-02

 

目录

一,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的前面申请四个字节的空间。此时释放的话虽然有内存泄漏的问题但是却不会因为报错而运行不下去。总结一句,就是释放内存的位置不对。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Cpp学习——动态内存管理 的相关文章

随机推荐

  • python数据评估

    未清理的数据 脏数据与杂乱数据 未清理数据分为两种 脏数据 也称为低质量数据 低质量数据存在内容问题 杂乱数据 也称为不整洁数据 不整洁数据存在结构问题 将数据可视化 例如 绘制图形 是编程评估的一部分 而非我们在这里说的目测评估 即通过目
  • NodeJs服务器启动后在浏览器访问时中文显示乱码处理方法

    创建一个叫 server js 的文件 并写入以下代码 使用 require 指令来载入 http 模块 并将实例化的 HTTP 赋值给变量 http var http require http 使用 http createServer 方
  • Dice相似系数(Dice Similarity Coefficient, DSC)

    Dice相似系数 Dice Similarity Coefficient DSC 分母可以解析为 FP TP 所有分类为阳性的样本 TP FN 真阳 假阴 所有真的是阳性的样本
  • LitJSON之JSON读取和写入

    JSON读取和写入 使用JsonReader例子 使用JsonWriter 目录 JSON读取和写入 一些开发者可能熟悉JSON数据的另一种处理方法 即通过利用类似流的方式来读取和写入数据 实现这种方法的是JsonReader类和 Json
  • jenkins+newman+postman持续集成环境搭建

    目录 一 Newman简介 二 Newman应用 三 安装newman 四 Html报告插件安装 五 安装nodejs 六 Jenkins集成步骤 一 Newman简介 Newman是一款基于Node js开发的 可以运用postman工具
  • jQuery的scroll

    scrollTop垂直滚动 scrollLeft水平滚动 scrollTop 读取或设置滚动条的y坐标 代码示例如下
  • echarts修改柱状图的宽度

    echarts修改柱状图的宽度 series bar barWidth 自适应 numberstring 柱条的宽度 不设时自适应 可以是绝对值例如 40 或者百分数例如 60 百分数基于自动计算出的每一类目的宽度 在同一坐标系上 此属性会
  • Hx711称重模块+STM32+CubeMX

    文章目录 一 模块和接线 二 CubeMX配置 1 时钟及sys 2 IO口 1 数据线DT设置为Input 2 时钟线SCK设置为Output 3 串口 4 后续配置 三 程序 1 main c 2 hx711 c 3 hx711 h 4
  • R(N)

    http acm hdu edu cn showproblem php pid 3835 Problem Description We know that some positive integer x can be expressed a
  • vue 动态修改margin-top_详解 vue 组件三大核心概念

    给前端大全加星标 提升前端技能 作者 前端工匠 公号 浪里行舟 本文来自作者投稿 前言 本文主要介绍属性 事件和插槽这三个vue基础概念 使用方法及其容易被忽略的一些重要细节 如果你阅读别人写的组件 可以从这三个部分展开 它们可以帮助你快速
  • 区块链学习(1) sha256算法 c语言实现

    sha256算法 网上有很多的介绍 摘抄一段如下 SHA 256 算法输入报文的最大长度不超过2 64 bit 输入按512 bit 分组进行处理 产生的输出是一个256 bit 的报文摘要 该算法处理包括以下几步 STEP1 附加填充比特
  • Python学习笔记——多线程

    mtsleepA import thread from time import sleep ctime loops 4 2 def loop nloop nsec lock print start loop nloop at ctime s
  • Node.js mm131图片批量下载爬虫1.00 iconv协助转码

    mm131图片批量下载爬虫1 00 2017年11月15日 内置http模块 var http require http 内置文件处理模块 用于创建目录和图片文件 var fs require fs 用于转码 非Utf8的网页如gb2132
  • java反射详解

    本篇文章依旧采用小例子来说明 因为我始终觉的 案例驱动是最好的 要不然只看理论的话 看了也不懂 不过建议大家在看完文章之后 在回过头去看看理论 会有更好的理解 下面开始正文 案例1 通过一个对象获得完整的包名和类名 1 2 3 4 5
  • STM32学习——FATFS文件系统

    目录 什么是文件系统 常用的文件系统 FATFS的特点 FATFS层次结构 移植步骤 相关配置宏 FATFS文件系统移植实验 FATFS程序结构图 FATFS底层设备驱动函数 宏定义 设备状态获取 设备初始化 读取扇区 扇区写入 什么是文件
  • 代码质量检测工具 QAPLug

    代码质量检测工具 情景 写完代码一定要别人review才发现bug或不好的语法或多余的变量是一件多么尴尬的事情 如果想在写代码时或者写代码后自己能发现问题 那么代码QA工具无疑是你必备的工具 工具 QAPlug就是一款实用十分方便的代码质量
  • [游戏] chrome 的小彩蛋

    在电脑上不了网时 chrome 显示无法显示此网页的同时 还会有一个小游戏可以玩 用户可以操作空格键来控制一只小恐龙让它跳过灌木丛
  • Python 实现逐步回归

    常用评价指标简介 当前统计学以计算机科学作为支撑 机器于人工的优势是计算速度 但机器无法自行判断运算何时退出 因此需要定量指标作为运算退出的标志 对于预测类的统计模型来说 常见的指标有赤池信息准则 AIC 贝叶斯信息准则 BIC R方 RO
  • 冒泡排序、选择排序、插入排序 原理及Java代码实现

    1 冒泡排序 冒泡排序 Bubble Sort 是一种计算机科学领域的较简单的排序算法 冒泡排序算法的原理如下 1 比较相邻的元素 如果第一个比第二个大 就交换他们两个 2 对每一对相邻元素做同样的工作 从开始第一对到结尾的最后一对 在这一
  • Cpp学习——动态内存管理

    目录 一 new 1 malloc realloc calloc的使用不便之处 2 new的好处 3 opreator new 二 delete 1 为什么要有delete 2 为什么要匹配使用 一 new 1 malloc realloc