C++内存管理

C语言内存管理方式在C++中可以继续使用,但是存在一定的缺陷,如使用malloc动态开辟自定义类型对象的空间,无法自动调用构造函数,那就必须我们去显示的调用构造函数(一般情况下,构造函数不可以显示调用,使用new定位表达式就可以做到显示调用)

free去释放空间,无法自动调用析构函数,也需要我们显示的调用析构函数,析构函数是可以直接显示调用的,但总归还是很麻烦

所以C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理

可以这样认为:new是封装之后的malloc,delete是封装之后的free

1 new/delete操作内置类型
 

void Test()
{//动态申请一个int类型的空间int* p1 = new int;//动态申请一个int类型的空间并初始化为4int* p2 = new int(4);//动态申请10个int类型的空间int* p3 = new int[9];delete p1;delete p2;delete[]p3;
}

对于内置类型,new就和malloc一样,不会初始化,但是我们可以手动给初值

给初值方式:

单个空间给初值的方式是在()里给值

连续空间给初值的方式是在{}里给值

void Test()
{int* p1 = new int(3);int* p2 = new int[5]{ 1,2,3 };int* p3 = new int[6]{};
}

 申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用
new[]和delete[]

2 new和delete操作自定义类型
 

对于自定义类型new完成:开空间+调用构造函数完成初始化

                            delete完成:释放空间+调用析构函数完成资源释放

class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A* p = new A;A* p2 = new A(4);A* p3 = new A[5];delete p;delete p2;delete[]p3;return 0;
}

 

 给初始值的方式:

//单个空间:A* m = new A(1);//连续空间://1 有名对象A a1(1);A a2(2);A* p = new A[4]{ a1,a2 };//2 匿名对象A* p2 = new A[4]{ A(1),A(2) };//3 隐式类型转换A* p3 = new A[4]{ 1,2 };delete m;delete[]p;delete[]p2;delete[]p3;

 

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与
free不会

总而言之,new和delete,new[],delete[]一定要匹配使用,不能乱来,一旦乱来结果是未定义的

错误示例:

class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A* p = new A[10];//free(p); 程序都崩溃delete p;return 0;
}

 原因:

因为有[],说明有多个对象,又存在我们自己显示写的析构函数,即使这个析构函数不会做任何事情,但编译器仍旧不会优化,所以会调用[]里面数字次析构函数

那么在开空间时,会开4*10+4个字节的空间,4个字节存整型,也就是[]里的数字,最终空间开好后返回图上指针的位置

free和delete释放空间的位置不对,释放空间要从起始位置开始一把释放,但它不是,故而程序崩溃

 

class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)" << endl;}
private:int _a;
};int main()
{A* p = new A[10];//free(p); 程序都没崩delete p;return 0;
}

 

没有显示写析构函数,编译器默认生成,又析构函数不会做任何事情,所以编译器直接优化,

只会开辟4*10个字节,不会多开4字节用于存储析构函数的调用次数,所以p指针指向了申请空间的起始位置,那么free和delete就不会报错 


3 operator new与operator delete函数
 

 

new和delete是用户进行动态内存申请和释放的操作符,operator newoperator delete
系统提供的全局函数new底层调用operator new全局函数来申请空间delete在底层通过
operator delete全局函数来释放空间

operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;

申请空间失败,则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常
 

operator delete 最终是通过free来释放空间
 

所以说new和delete实际上是对malloc和free的封装

4 new和delete的实现原理
 

1 内置类型
 

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,需要注意的是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请和释放的是连续空间,而且new申请空间失败时会抛异常,malloc会返回NULL

2 自定义类型
 

new的原理


1. 调用operator new函数申请空间
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来释
放空间
 

5 定位new表达式(placement-new)
 

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象

使用格式
 

new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表
 

使用场景:


定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如
果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化
 

    A* p = (A*)malloc(sizeof(A));new(p)A;//构造函数不可以显示调用,但可以用定位new表达式p->~A();//析构函数可以显示调用free(p);A* p2 = (A*)operator new(sizeof(A));new(p2)A(4);//显示调用构造函数时可以传参p2->~A();operator delete(p2);return 0;

6 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在释放空间前会调用析构函数完成
空间中资源的清理

捕获异常:

    try{char* a = new char[0x7fffffff];}catch(const exception&e){cout << e.what() << endl;}

 

不捕获异常程序直接崩掉

也可以间接捕获,如:

void func()
{char* a = new char[0x7fffffff];
}int main()
{try{func();}catch(const exception&e){cout << e.what() << endl;}return 0;
}

7 内存泄漏
 

1 内存泄漏的概念及危害

概念:

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

危害:

长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现
内存泄漏会导致响应越来越慢,最终卡死

2 内存泄漏分类(了解)
 

堆内存泄漏(Heap leak)
 

堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一
块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分
内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak
 

系统资源泄漏
 

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【多线程初阶】多线程案例之单例模式

文章目录 前言1. 什么是单例模式2. 饿汉模式3. 懒汉模式 --- 单线程版4. 懒汉模式 --- 多线程版5. 懒汉模式 --- 多线程改进版总结 前言 本文主要给大家讲解多线程的一个重要案例 — 单例模式. 关注收藏, 开始学习吧&#x1f9d0; 1. 什么是单例模式 单例模式是一种很经典的…

JVM的组件、自动垃圾回收的工作原理、分代垃圾回收过程、可用的垃圾回收器类型

详细画的jvm模型图 https://www.processon.com/diagraming/64c8aa11c07d99075d934311 官方网址 https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html 相关概念 年轻代是所有新对象被分配和老化的地方。当年轻代填满时&#xff0c;这会导致m…

活动目录密码更改

定期更改密码是一种健康的习惯&#xff0c;因为它有助于阻止使用被盗凭据的网络攻击&#xff0c;安全专家建议管理员应确保用户使用有效的密码过期策略更改其密码。 管理员可以通过电子邮件通知用户在密码即将过期时更改其密码&#xff0c;但在许多组织中&#xff0c;用户只能…

web流程自动化详解

今天给大家带来Selenium的相关解释操作 一、Selenium Selenium是一个用于自动化Web浏览器操作的开源工具和框架。它提供了一组API&#xff08;应用程序接口&#xff09;&#xff0c;可以让开发人员使用多种编程语言&#xff08;如Java、Python、C#等&#xff09;编写测试脚本&…

应用层协议——https

文章目录 1. HTTPS 是什么2. 什么是"加密"3. 常见的加密方式4. 数据摘要 && 数字签名5. HTTPS 的工作过程探究5.1 方案1 - 只使用对称加密5.2 方案2 - 只使用非对称加密5.3 方案3 - 双方都使用非对称加密5.4 方案4 - 非对称加密 对称加密5.5 中间人攻击5.6 …

Mac提示文件:已损坏,无法打开。你应该把它移到废纸篓

文章目录 一、电脑信息二、打开任何来源设置三、更改应用程序拓展属性 一、电脑信息 我的是新版的Venture 13的系统。UI改的比较多。与之前的配置还是有很大的区别的。 打开下载的软件&#xff0c;显示已经损坏&#xff0c;打不开。抛开软件本身的问题外&#xff0c;一般是Ma…

【数据结构与算法】TypeScript 实现图结构

class Grapg<T> {// 用于存储所有的顶点verteces: T[] [];// 用于存储所有的边 采用邻接表的形式adjList: Map<T, T[]> new Map();// 添加顶点addVertex(v: T) {this.verteces.push(v);// 初始化顶点的邻接表this.adjList.set(v, []);}// 添加边addEdge(v: T, w:…

文心一言 VS 讯飞星火 VS chatgpt (68)-- 算法导论6.5 7题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;68&#xff09;-- 算法导论6.5 7题 七、试说明如何使用优先队列来实现一个先进先出队列&#xff0c;以及如何使用优先队列来实现栈(队列和栈的定义见 10.1 节。) 文心一言&#xff1a; 优先队列是一种数据结构&#xff0c;其中…

无人机机巢有哪些,无人机机场/机场的主要分类

随着无人机技术的飞速发展&#xff0c;无人机已经渗透到了物流、农业、救援、公共安全等多个领域。而为了使这些无人机能更加高效、灵活地运行&#xff0c;一个新的概念应运而生&#xff0c;那就是无人机机巢&#xff08;UAV Nest&#xff09;。复亚智能无人机机巢是一种供无人…

GitLab备份升级

数据备份(默认的备份目录在/var/opt/gitlab/backups/下&#xff0c;生成一个以时间节点命名的tar包。) gitlab-rake gitlab:backup:create新建repo源&#xff0c;升级新版本的gitlab vim /etc/yum.repos.d/gitlab-ce.repo [gitlab-ce] namegitlab-ce baseurlhttps://mirrors.…

【大数据】-- docker 启动 mysql 5.7,开启 binlog

1.说明 mysql binlog&#xff1a;二进制日志文件。它有两个作用&#xff0c;一是增量备份&#xff0c;即只备份新增的内容&#xff0c;可以用于恢复数据&#xff1b;二是用于主从复制等&#xff0c;即主节点维护了一个binlog日志文件&#xff0c;从节点从binlog中同步数据。 …

嵌入式pc技术的特点有哪些?

嵌入式PC技术是将计算机硬件和软件嵌入到各种设备中的一种技术&#xff0c;它具有低功耗、高效率、小型化、易于集成等优点&#xff0c;广泛应用于工业自动化、医疗设备、电力、通信、家用电器、物联网等领域&#xff0c;成为新时代工业生产和社会生活必不可少的技术之一。 嵌入…

使用idea实现git操作大全(在项目开发中遇到的实际情况

使用idea实现git操作大全&#xff08;在项目开发中遇到的实际情况&#xff09; 1.安装git插件2.在开发中切记拉一个自己的分支 1.安装git插件 2.在开发中切记拉一个自己的分支 选中需要拉的分支&#xff0c;右键该分支&#xff0c;选中new breach from “分支”&#xff0c;点…

接口测试如何在json中引用mock变量

在测试接口的时候&#xff0c;有的接口需要测试随机传入大量数据&#xff0c;查看数据库是否正常&#xff0c;但是大量的随机数据全靠自己手写会很慢&#xff0c;而且是通过json传递的数据。 这里我们就可以使用mock生成随机变量&#xff0c;然后在json中引用mock变量 首先看…

Reinforcement Learning with Code 【Code 1. Tabular Q-learning】

Reinforcement Learning with Code 【Code 1. Tabular Q-learning】 This note records how the author begin to learn RL. Both theoretical understanding and code practice are presented. Many material are referenced such as ZhaoShiyu’s Mathematical Foundation o…

leetcode 135. 分发糖果

2023.8.1 这道题只从前向后遍历会出各种问题&#xff0c;所以最后决定向前向后各遍历一次。 先定义一个饼干数组biscuits&#xff0c;记录每个孩子的饼干数量&#xff0c;初始化每个孩子饼干数量为1。 然后从前向后遍历、从后向前遍历&#xff0c;使其满足“相邻两孩子评分更高…

前端Vue入门-day08-vant组件库

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 vant 组件库 安装 导入 全部导入 按需导入 浏览器配饰 Viewport 布局 Rem 布局适配 vant 组件库 …

NASM汇编

1. 前置知识 1. 汇编语言两种风格 intel&#xff1a;我们学的NASM就属于Intel风格AT&T&#xff1a;GCC后端工具默认使用这种风格&#xff0c;当然我们也可以加选项改成intel风格 2. 代码 1. 段分布 .text: 存放的是二进制机器码&#xff0c;只读.data: 存放有初始化的…

sublime配置less的一些坑(1)

仅在sublime的Install Package安装保存less报错 在sublime的Install Package安装less 打开sublime软件,按住CtrlShiftP组合键,弹出的界面中选择Install Package 选中后enter或者回车。等会弹出一个弹窗,大致意思是说你已经成功安装了package control。如果你在此之前已经安装了…

MySQL之深入InnoDB存储引擎——物理文件

文章目录 一、参数文件二、日志文件三、表结构定义文件四、InnoDB 存储引擎文件1、表空间文件2、重做日志文件 一、参数文件 当 MySQL 实例启动时&#xff0c;数据库会先去读一个配置参数文件&#xff0c;用来寻找数据库的各种文件所在位置以及指定某些初始化参数。在默认情况…