C++初阶教程——C++内存管理

news2024/11/5 16:27:11

一、C语言动态内存管理

#include <iostream>
using namespace std;

int main()
{
	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);
}

        C语言中,存在三个用于动态分配内存的函数 :

  1. malloc函数
    1. 用途:分配一块未初始化的内存。
    2. void *malloc(size_t size);
    3. 特点:分配的内存是未初始化的,可能是之前使用过的数据,需要手动初始化;如果分配失败,返回NULL。
  2. calloc函数
    1. 用途:分配并初始化一块指定大小的内存区域,所有位都被设置为 0。
    2. void *calloc(num,size_t size);
    3. 特点:num表示元素的数量,size表示每个元素的大小;分配的内存区域被初始化为0;分配失败返回NULL。

  3. realloc函数
    1. 用途:重新分配一块内存区域的大小,可以增加或者减少原本的内存块。
    2. void *realloc(void *ptr, size_t new_size);
    3. ptr表示之前通过动态内存分配的区域指针;new_size表示新的内存区域的大小;如果ptr为NULL则realloc行为类似于malloc,即分配一块新内存;如果new_size为0则行为类似于free,即回收一块内存;如果分配内存失败,返回NULL,并且保持原来的内存区域不变。

使用场景

  • malloc:当你需要分配一块内存,并且不需要初始化或者需要非零的初始值时。
  • calloc:当你需要分配一块内存,并且希望这块内存的内容是确定的(例如,初始化为 0)。
  • realloc:当你需要改变已经分配的内存块的大小,或者在程序运行时动态调整内存使用时。
int* p1 = (int*)malloc(sizeof(int));
free(p1);

        free函数用来释放通过malloc、calloc和realloc函数动态分配的内存区域;它只有一个参数——指向需要释放的内存的指针没有任何返回值;当动态内存不再被需要时,应当使用free函数来释放这块内存避免内存泄漏

二、C++内存管理

        C语言内存管理方式在C++里是可以继续使用的,但是C语言的动态内存分配函数在初始化方面有些无能为力。C语言的内存管理方式无法满足自定义类型的动态内存管理需要,类的初始化是需要调用构造函数,而C管理方式不能调用构造函数。

        C++提出了新的内存管理方式:通过newdelete操作符进行动态内存管理。

2.1new/delete操作内置类型

void test()
{
    //动态申请一个int类型的空间
    int *ptr1 = new int;
    //动态申请一个int类型的空间并出示化为10
    int *ptr2 = mew(10);
    //动态申请10个int类型的空间
    int *ptr3 = mew int[10];

    delete ptr1;
    delete ptr2;
    delete[] ptr3;
}

        申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],一定要匹配起来使用。 

2.2new/delete操作自定义类型 

#include <iostream>
using namespace std;

class A
{
public:
	A(int a = 10) :k(a)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int k;
};

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

        new/delete与malloc/free最大的区别就是,前者对于自定义类型除了开空间之外还会调用构造函数和析构函数。

三、operator new和operator delete函数

        new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数。new操作符在底层调用operator new 全局函数来申请空间,对于自定义类型还会调用构造函数。

void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	// try to allocate size bytes
	void* p;
	while ((p = malloc(size)) == 0)
		if (_callnewh(size) == 0)
		{
			// report no memory
			// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}

        看不懂没关系,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间

        注意:这里的operator new不是重载的意思

四、new和delete的实现原理

4.1内置类型

        如果申请的是内置类型的空间,new和malloc,delete和free基本类似。不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]释放的是连续空间,而且new在申请空间失败时会抛出异常

4.2自定义类型

  • new的原理
    1. 调用operator函数申请空间。
    2. 在申请的空间上执行构造函数,完成对象的构造。
  • delete的原理
    1. 在空间上执行析构函数,完成对象中资源的清理工作。
    2. 调用operator delete函数释放对象的空间。
  • new T[N]的原理
    1. 调用operator new[]函数,在operator new[]函数中实际调用operator new函数完成N个对象空间的申请。
    2. 在申请的空间上执行N次构造函数。
  • delete[]的原理
    1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。
    2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间。

五、定位new表达式(placement-new)

        定位new表达式,是一种特殊的内存分配技术,它允许在已经分配的内存上构造对象。这种技术用于重用已经分配的内存,或者在特定的内存区域创建对象。

#include<iostream>
using namespace std;
class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};
// 定位new/replacement new
int main()
{
	// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
	A* p1 = (A*)malloc(sizeof(A)*2);
	// 注意:如果A类的构造函数有参数时,此处需要传参
	new(p1)A; 
    //在内存的下一个位置构造对象。
	new(p1 + 1)A;
	p1->~A();
	free(p1);
	A* p2 = (A*)operator new(sizeof(A));
	new(p2)A(10);
	p2->~A();
    //也可以显式调用
	operator delete(p2);
	return 0;
}

六、malloc/free和new/delete的区别

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的是

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

七、内存泄漏

7.1什么是内存泄漏

        内存泄漏是指因为疏忽或者错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段的控制,因而造成了内存的浪费。

        内存泄漏会导致长期运行的程序响应越来越慢,最终卡死。

7.2内存泄漏分类

  • 堆内存泄漏(Heap Leak)

        堆内存是指通过malloc/calloc/realloc/new等从堆中分配的一块内存,用完之后必须通过调用相应的free和delete释放。加入程序的设计错误导致没有被释放,那么这部分空间将无法再被使用,导致堆内存泄露。

  • 系统资源泄漏

        指程序使用系统分配的资源,比如套接字、文件描述符、管道等没有使用相应的函数释放掉,导致系统资源的浪费,严重的可导致系统性能降低,系统执行不稳定。

八、关于delete[]

        delete[]是怎么知道要调用多少次delete函数的呢?

A* ptr = new A[10];

        在这段代码中,实际上new[]不只申请了10个类类型的大小,它额外申请了4个字节用来存放开辟空间的数目,这四个字节在返回的地址之前。

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

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

相关文章

STM32HAL-最简单的长、短、多击按键框架(多按键)

概述 本文章使用最简单的写法实现长、短、多击按键框架,非常适合移植各类型单片机,特别是资源少的芯片上。接下来将在stm32单片机上实现,只需占用1个定时器作为时钟扫描按键即可。 一、开发环境 1、硬件平台 STM32F401CEU6 内部Flash : 512Kbytes,SARM …

【论文精读】LPT: Long-tailed prompt tuning for image classification

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;论文精读_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 摘要 2. …

队列的模拟实现

概念&#xff1a; 队列 &#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出 FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为 队尾&#xff08; Tail/Rear &#xff09; 出队列&a…

Centos安装配置Jenkins

下载安装 注意&#xff1a;推荐的LTS版本对部分插件不适配&#xff0c;直接用最新的版本&#xff0c;jenkins还需要用到git和maven&#xff0c;服务器上已经安装&#xff0c;可查看参考文档[1]、[2]&#xff0c;本次不再演示 访问开始使用 Jenkins 下载jenkins 上传至服务器…

在Python中最小化预测函数的参数

在 Python 中&#xff0c;最小化预测函数的参数通常涉及使用优化算法来调整模型的参数&#xff0c;以减少预测误差。下面介绍几种常见的方法来实现这一目标&#xff0c;主要使用 scipy 和 numpy 库。 1、问题背景 我正在尝试通过解决自己想出的问题来学习Python&#xff0c;我…

统信UOS系统应用开发

包括cpu 、内存 、安全等接口描述。 文章目录 一、内存管理非文件形式的内存动态函数库调用接口二、cpu内置安全飞腾国密加速硬件用户态驱动API说明真随机数真随机数三、cpu多核调度cpu亲和性获取接口用于cpu set集操作的相关宏定义一、内存管理 非文件形式的内存动态函数库调…

postman 获取登录接口中的返回token并设置为环境变量的方法 postman script

postman是一个比较方便的API开发调试工具&#xff0c; 我们在访问API时一般都需要设置一个token来对服务进行认证&#xff0c; 这个token一般都是通过登录接口来获取。 这个postman脚本放到登录接口的sctipt--> post-response里面即可将登陆接口中返回的token值设置到postma…

《华为工作法》读书摘记

无论做什么事情&#xff0c;首先要明确的就是做事的目标。目标是引导行动的关键&#xff0c;也是证明行动所具备的价值的前提&#xff0c;所以目标管理成了企业与个人管理的重要组成部分。 很多时候&#xff0c;勤奋、努力并不意味着就一定能把工作做好&#xff0c;也并不意味…

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏

【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏 目录 文章目录 【大语言模型】ACL2024论文-07 BitDistiller: 释放亚4比特大型语言模型的潜力通过自蒸馏目录摘要研究背景问题与挑战如何解决创新点算法模型实验效果代码推荐阅读指数&…

Tomcat 和 Docker部署Java项目的区别

在 Java 项目部署中&#xff0c;Tomcat 和 Docker 是两种常见的选择。虽然它们都可以用来运行 Java 应用&#xff0c;但它们在定位、部署方式、依赖环境、资源隔离、扩展性和适用场景等方面有显著区别。 1. 功能定位 1.1 Tomcat Apache Tomcat 是一种轻量级的 Java 应用服务器…

基于SSM的学生选课系统+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

Java I/O流详解

文章目录 I/O流概念I/O流的分类字节流&#xff08;Byte Streams&#xff09;字节字节流概述方法主要类和继承关系示例代码字节流读取文件 字符流字符流概述子类Reader1.FileReader&#xff1a;2.CharArrayReader&#xff1a;3.StringReader&#xff1a;4.InputStreamReader&…

基于Multisim数字频率计频率范围0-9999HZ电路(含仿真和报告)

【全套资料.zip】数字频率计仿真电路设计Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 1.采用纯数字电路&#xff0c;非单片机。 2.频率计测量的频率范围0-9999HZ。 3.使用数码管进行频…

Python画笔案例-095 绘制鼠标画笔

1、绘制 鼠标画笔 通过 python 的turtle 库绘制 鼠标画笔,如下图: 2、实现代码 绘制 鼠标画笔,以下为实现代码: """鼠标画笔.py本程序可以用鼠标指针在屏幕上画画儿。 """ import turtlescreen = turtle.getscreen() screen.setup(

【温酒笔记】SPI

1. SPI基础 物理层 片选线 &#xff1a;选中拉低SCK: 时钟线MOSI:主出从入MISO:主入从出 协议层 CPOL:时钟极性&#xff1a;空闲电平高低 CPHA:时钟相位&#xff1a;第一个还是第二个边沿采样 2. 示例SPI-W25Q16 (见模组分类下文章)

mac电脑设置crontab定时任务,以及遇到的问题解决办法

crontab常用命令 crontab -u user&#xff1a;用来设定某个用户的crontab服务&#xff1b; crontab file&#xff1a;file是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件&#xff0c;crontab命令将接受标准输入&#xf…

MySQL中,如何定位慢查询?定位到的慢SQL如何分析?

目录 1. 慢查询发生的场景&#xff1f; 2. MySQL中&#xff0c;如何定位慢查询&#xff1f; 2.1 详细解释 3. 定位到的慢SQL如何分析&#xff1f; 3.1 详细说明 1. 慢查询发生的场景&#xff1f; 2. MySQL中&#xff0c;如何定位慢查询&#xff1f; 介绍一下当时产生问题…

大数据新视界 -- 大数据大厂之提升 Impala 查询效率:索引优化的秘籍大揭秘(上)(3/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

Nico,从零开始干掉Appium,移动端自动化测试框架实现

开头先让我碎碎念一波~去年差不多时间发布了一篇《 UiAutomator Nico&#xff0c;一个基于纯 adb 命令实现的安卓自动化测试框》&#xff08;https://testerhome.com/topics/37042&#xff09;&#xff0c; 由于种种原因 (详见此篇帖子) 当时选择了用纯 adb 命令来实现安卓自动…

小样本语义分割(HDMNet网络)

小样本语义分割&#xff08;HDMNet网络&#xff09; 摘要HDMNet 解决的问题本文贡献HDMNet 模型1. 特征提取2. 解耦下采样和匹配模块&#xff08;分层匹配结构&#xff09;2.1. 粗粒度到细粒度解码器2.2 . 自注意力模块2.3. 相关性模块 3. 损失函数 总结 摘要 小样本语义分割&…