c++内存管理:

news2024/11/19 7:32:26

目录

new和delete

使用方法:

注意事项:

new申请不需要检查返回值

operator new和operator delete函数的讲解


c语言申请内存有哪些方法:

答:malloc  calloc realloc三种

#include<stdlib.h>
void test()
{
	int*p1 = (int*)malloc(sizeof(int));
	free(p1);
	int*p2 = (int*)calloc(4, sizeof(int));
	int *p3 = (int*)realloc(p2, sizeof(int)* 10);
	free(p3);
}

其中,malloc就是普通的动态内存申请

calloc相当于malloc加上memset把申请的空间全部初始化为0

realloc相当于内存扩容,分为异地扩容和原地扩容,当扩容的次数少,空间小时,会执行原地扩容,当扩容的次数多,空间大时,会执行异地扩容。

原地扩容和异地扩容的区别?

答:如上图代码所示,p2和p3指针指向同一块空间,而异地扩容则不然,异地扩容会先找一块新的空间,然后把原空间的内容拷贝到新空间位置,然后释放掉原空间,所以返回的就是p3.

new和delete

使用方法:

c++是通过什么申请内存的呢?

答:c++是通过两个关键字(操作符)来申请和释放空间的。

new和delete

int main()
{
	int *p1 = new int;
	delete p1;
	return 0;
}

相当于这里申请一个字节的空间,返回指向该空间的指针p1,然后delete表示释放空间。

注意:这里申请空间并不会对空间上的内容完成初始化:

例如:

 我们申请的空间并没有进行初始化。

我们如何申请空间的同时并初始化呢?

答:我们可以这样操作

例如:

int main()
{
	int *p1 = new int(0);
	delete p1;
	return 0;
}

 我们在后面加上0表示申请空间并把空间初始化为0.

我们如何申请多个空间呢?

答:

int main()
{
	int *p1 = new int[10];
	delete[] p1;
	return 0;
}

这里表示我们要申请十个整型空间,注意:我们在delete释放时,要和我们申请的空间进行一一对应。

 假如我们要对申请的多个空间进行初始化呢?

答:我们可以这样写:

int main()
{
	int *p1 = new int[10]{1, 2, 3, 4};
	delete[] p1;
	return 0;
}

这里表示我们对申请的十个空间中的前4个进行初始化:

 我们发现,对于内置类型,这里的new和delete和c语言的动态内存申请函数本质上没什么区别,那为什么++要定义这两个关键字呢?

答:对于内置类型,c语言和c++的动态内存申请本质是一样的,但是对于自定义类型,结果就不同了

例如:

我们写一个简单的类:

class A
{
	A(int a = 0)
	:_a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};

这个类中有两个成员函数,分别是构造函数和析构函数,函数的目的是当调用构造和析构函数,打印对应的提示并打印出this指针。

我们进行实验:

int main()
{
	/*int *p1 = new int[10]{1, 2, 3, 4};
	delete[] p1;
	return 0;*/
	A* p1 = new A;
	
}

我们动态内存申请一个类的空间,返回指向该空间的指针p1

我们进行编译:

 这里表示我们的动态内存申请new调用了构造函数。

但是我们的malloc是不会调用构造函数的:

int main()
{
	/*int *p1 = new int[10]{1, 2, 3, 4};
	delete[] p1;
	return 0;*/
	/*A* p1 = new A;*/
	A*p1 = (A*)malloc(sizeof(A));
}

我们进行编译:

 所以new相较于malloc对于自定义类型来说,new会调用自定义类型的构造函数,而malloc不会。

new会调用自定义类型的构造函数,那么delete是不是也会调用析构函数?

答:会:

int main()
{
	/*int *p1 = new int[10]{1, 2, 3, 4};
	delete[] p1;
	return 0;*/
	A* p1 = new A;
	/*A*p1 = (A*)malloc(sizeof(A));*/
	delete p1;
}

我们进行调用:

 所以delete也会调用自定义类型的析构函数。

我们举一个之前写的链表的例子:

struct ListNode
{
	ListNode(int val = 0)
	:_next(nullptr)
	, _val(val)
	{}
	ListNode* _next;
	int _val;
};

我们现在可以这样写链表:

struct和class都是类关键字,struct当我们不处理时,类中的成员的默认用public修饰。

我们可以在类中写构造函数,相当于我们之前的创建新节点

int main()
{
	ListNode*n1 = new ListNode(1);
	ListNode*n2 = new ListNode(2);
	ListNode*n3 = new ListNode(3);
	ListNode*n4 = new ListNode(4);
	n1->_next = n2;
}

这样写链表就会方便很多。

注意事项:

注意:

new和delete一定要匹配,否则会产生意想不到的问题,我们就只举一个例子:

例如:

nt main()
{
	A*p1 = new A[10];
	delete p1;
}

我们写出这样的代码进行运行就会报错:

为什么会这样呢?

我们先写一个正常的进行分析:

 

int main()
{
	A*p1 = new A[10];
	delete[] p1;
}

我们的A的成员只有一个整型,所以A占四个字节的空间,十个A就占40个字节的空间。

 我们先进行编译:

 我们进行申请时或进行释放时,都会调用多次调用构造函数或析构函数。

我们在创建时,知道我们需要创建十个A类所占的空间

但是我们在析构的时候,并不清楚我们需要析构多少次,这时候,我们需要额外申请一个整型的空间:

 接下来,我们把p1往前置:

 这时候,我们就知道我们需要析构多少次,并且从这里可以把我们申请的空间全部释放。

我们返回来看之前报错的情况:

 

int main()
{
	A*p1 = new A[10];
	delete p1;
}

为什么会报错呢?

答: 因为我们释放没有写[],所以我们构造了十次,但是我们不清楚析构了多少次,所以就会报错。

上面的这些都是关于编译器vs2013的一些情况,举这些例子只是为了说明一定要把申请的空间和delete释放的空间进行对应

new申请不需要检查返回值

我们知道malloc申请大的空间或者连续申请小的空间就会报错:

int main()
{
	while (1)
	{
		int *p1 = (int*)malloc(1024 * 1024);
		if (p1)
		{
			cout << p1 << endl;
		}
		else
		{
			cout << "申请失败" << endl;
			break;
		}
	}
}

并且我们知道,当malloc申请失败的时候,会返回空指针,所以我们可以写出以上代码来进行实验:

 

 申请多次的时候,报错

接下来,我们对new进行实验:

int main()
{
	while (1)
	{
		int *p1 = new int[1024 * 1024];
		if (p1)
		{
			cout << p1 << endl;
		}
		else
		{
			cout << "申请失败" << endl;
			break;
		}
	}
}

 运行很快就停止了,但是并没有打印出申请失败,说明我们new失败的返回值并不是0,或者说,new失败没有返回值。

new失败的话,就会抛异常,所以我们不需要对返回值进行检查,对于抛异常的问题,我们之后再进行详解。

operator new和operator delete函数的讲解

上述的两个函数是new和delete的底层实现:

 new的底层实现就是通过new调用operator new函数,operator函数中有malloc,调用完毕之后调用构造函数。

注意:operator new函数并不是new的重载。

operator new相当于是一个新的全局函数。

我们看一下operator函数的定义:

 我们可以发现,operator new函数就是malloc函数的封装,无非就是加上了当申请失败时,不反回,而是抛异常。

我们观察一下operator delete函数。

 相当于我们operator的主体部分也是调用了free函数。

我们是否可以使用operator new来申请空间呢?

答:可以:

例如:

int main()
{
	while (1)
	{
		char*p1 = (char*)operator new(1024 * 1024 * 1024);
		cout << (void*)p1 << endl;
	}
}

operator new的使用方法和malloc相似。

不同点在于:operator new申请失败的话不需要报错,因为会抛异常。

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

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

相关文章

Day11-尚品汇-退出登录

1.在Header组件里面&#xff1a; 1》绑定一个click事件 2》写其触发的方法 2.发请求通知服务器 1》先观察文档 2》.在api里面写代码&#xff1a; 3》在store仓库user.js里面也要写代码&#xff1a; 1&#xff09; 不单单向服务器发请求清除token&#xff0c;而且需要清除use…

【MLOPs】Docker

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

Python基础加强学习

一、python概述 1. python的应用领域 web开发大数据处理人工智能自动化运维开发云计算爬虫游戏开发 2. 安装python 要进行python开发&#xff0c;首先要安装python解释器&#xff0c;这里说的安装python说的就是安装python的解释器。 测试python是否安装成功&#xff0c;在…

基于springboot的校园二手网站

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

过滤器和拦截器的区别

目录 1 前言 2 区别 2.1 实现原理不同 2.2 使用范围不同 2.3 执行顺序不同 4 注入Bean的情况不同 1 前言 可能有些小伙伴们在接手公司的项目时&#xff0c;经常看到公司的项目中既有过滤器又有拦截器&#xff0c;那么它们既然都拦截的作用&#xff0c;那么各自扮演着什么…

pyinstaller打包出错记录

稍微记录一下最近在liunx上pyinstaller打包出错 目录稍微记录一下最近在liunx上pyinstaller打包出错1 号坑 Python3.7.0安装2号坑 成功打包但是执行失败小结后面代码的环境是在Windows子系统下的Ubuntu 20.04下进行的。vscode可以通过&#xff0c;配置WSL来进入环境&#xff08…

Pytorch+Python实现人体关键点检测

用PythonPytorch工程代码对人体进行关键点检测和骨架提取&#xff0c;并实现可视化。 使用背景&#xff1a; 物体检测为许多视觉任务提供动力&#xff0c;如实例分割、姿态估计、跟踪和动作识别。它在监控、自动驾驶和视觉答疑中有下游应用。当前的对象检测器通过紧密包围对象…

深度学习提高模型准确率方法

这里写目录标题深度学习数据使用更多数据更改图像大小减少颜色通道算法模型改进增加训练轮次迁移学习添加更多层调整超参数总结深度学习 我们已经收集好了一个数据集&#xff0c;建立了一个神经网络&#xff0c;并训练了模型&#xff0c;在测试和验证阶段最后得到的准确率不高…

8086通用寄存器

目录 概述 EU&#xff1a;负责执行指令完成两种操作&#xff1a;算数逻辑运算&#xff0c;计算存储器操作数的偏移地址 BIU&#xff1a;完成所有的总线操作 寄存器 AX BX CX DX SP,BP,SI,DI IP CS&#xff0c;DS&#xff0c;SS&#xff0c;ES 概述 8086和8088C…

神经网络每次结果不一样,神经网络预测问题

1、求助&#xff1a;神经网络两次训练的结果不一样 神经网络两次训练的结果不一样&#xff0c;这是因为每次训练的迭代初值不相同&#xff08;是随机的&#xff09;&#xff0c;所以得到的结果是有差异的。一般的话&#xff0c;软件开启第一次时&#xff0c;运行得到结果是比较…

Java | 学习笔记02 快速之旅

运行已经开发好的Java程序&#xff0c;只需要JRE&#xff08;Java运行时环境&#xff09;就可以。但事实上&#xff0c;要想完成一个Java程序的开发&#xff0c;我们至少需要安装好JDK 目录 一、Java环境配置 1.下载JDK 2.配置环境变量 二、Hello World&#xff01; 三、I…

关于C++、C++ CLI, Java、C# 的自定义类实现列表初始化。

1、C DList_类构造函数 /// <summary> /// 表表初始化 dList<int> idl {1,2,3,4}; /// </summary> /// <typeparam name"T"></typeparam> /// <param name"tList"></param> template<class T> inline …

一只脚踏进Java的大门

一杯热气腾腾的咖啡&#xff0c;没错&#xff0c;这就是Java的标志。学习Java&#xff0c;我们就从这杯咖啡开始。2022年10月24日&#x1f6a9; Hello Java!一、认识Java从Hello world开始二、运行Java程序1、编译运行原理2、JDK、JRE、JVM以及它们之间的关系3、运行步骤展示三…

C语言-简单的程序设计

&#x1f31e;欢迎来到C语言的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f320;本阶段属于练气阶段&#xff0c;希望各位仙友顺利完成…

docker 网络

前言 随着容器的普及&#xff0c;经常使用docker创建容器来跑应用&#xff0c;结合开源的kubernetes和istio等&#xff0c;对于无状态的服务有极好的支持能力&#xff0c;秒级调度&#xff0c;弹性伸缩等优势。实际上kube的容器仅仅是接口&#xff0c;实际的容器可以是docker&…

布隆过滤器

文章目录前导布隆过滤器特点映射方式hash 函数BloomFiltersettestreset相关问题应用示例哈希切分例子今天是1024程序员节,祝各位节日快乐啦!!!前导 我们之前使用位图bitset,只能将一个整数映射到比特位上&#xff0c;来判断某个数是否存在 但是假如我们也想把判断一个字符串是…

【Linux】yum 与 vim 的基本使用

文章目录一、yum 背景知识1、商业生态2、开源生态3、软件生态本土化二、yum 的基本使用1、查看软件包2、安装软件3、卸载软件三、vim 的基本使用1、vim 的基本概念2、vim 的基本操作2.1 模式间切换2.2 光标定位2.3 文本复制2.4 文本编辑2.5 底行模式的操作四、简单 vim 配置2、…

前端工程化<npm、cnpm、yarn、npx、pnpm等包管理工具>

平时工作中&#xff0c;像npm、cnpm、yarn等一些工具都是经常经常用的&#xff0c;但可能对里面的一些细节都没太在意&#xff0c;所以这篇就来总结一下加深印象和理解。另外还有pnpm的使用&#xff0c;以及它的优势 1. npm包管理工具 包管理工具npm Node Package Manager&a…

『Halcon与C#混合编程』011_工业相机的SDK介绍

这里以淘宝上的显微精工店铺的相机为例(支持SDK) 一、相机的SDK简单介绍 第一步:安装好驱动,并能正常打开相机 第二部:找到相机的安装目录,查看厂家提供的Demo和开发手册 在Demo中找到C#的Demo,运行Demo.sln 第三步

基于Matlab使用粒子滤波器和高斯滤波器跟踪单个对象(附源码)

此示例说明了如何使用粒子滤波器和高斯和滤波器来跟踪使用仅范围测量的单个对象。 一、介绍 只能观察范围信息的传感器无法通过单次检测提供对物体状态的完整了解。此外&#xff0c;当以笛卡尔坐标系表示时&#xff0c;仅范围测量的不确定性是非高斯的&#xff0c;并产生凹形…