【C++笔记】内存管理

前言

各位读者朋友们大家好,上期我们讲了类和对象下的内容,类和对象整体的内容我们就讲完了,接下来我们开启新的部分内存管理的讲解。

目录

  • 前言
  • 一. C/C++内存分布
  • 二. C语言中内存管理的方式
  • 三. C++内存管理方式
    • 3.1 new/delete操作内置类型
    • 3.2 new和delete操作自定义类型
  • 四. operator new和operator delete函数
    • 4.1 operate new和 operator delete函数
  • 五. new和delete的实现原理
    • 5.1 内置类型
    • 5.2 自定义类型
    • 5.3 使用不匹配
  • 六. 定位new表达式
  • 七. malloc/free和new/delete的区别
  • 结语

一. C/C++内存分布

C/C++的内存分为堆区、栈区、静态区和常量区,我们先来看下面的一段代码和相关问题:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二. C语言中内存管理的方式

malloc/calloc/relloc的区别:

  • malloc是用来在堆区开辟指定字节的函数,返回的是void * 类型的指针。
    在这里插入图片描述
  • calloc函数是用来开辟指定字节空间的函数,并且把开辟的空间的值赋值为0,返回值也是void * 类型的指针。
    在这里插入图片描述
  • realloc函数是用来扩容的函数,第一个形参是要扩容的初始位置的指针,第二个参数是扩容后的空间大小,特别的如果第一个参数传的是空指针,那么realloc函数的功能等同于malloc函数的功能。如果原地扩容成功就返回传过去的指针,如果没有成功就会异地扩容,将原来的数据拷贝到新的位置,再将原位置的空间释放后返回新空间的地址。
    在这里插入图片描述
    在这里插入图片描述
    这里不需要释放p2,因为p3是在p2的基础上扩容的,如果原地扩容成功,p2和p3指向的空间是同一块,所以只需要释放p3即可;如果异地扩容,realloc函数就已经帮我们将p2释放了。

三. C++内存管理方式

C语言的内存管理方式在C++中可以继续使用,但是有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行内存管理。

  • new 运算符用于在堆(heap)上动态分配内存并初始化对象。它返回指向分配的内存块的指针。
  • delete 运算符用于释放先前使用 new 运算符分配的内存。

3.1 new/delete操作内置类型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],一定要搭配起来使用

3.2 new和delete操作自定义类型

在这里插入图片描述
在这里插入图片描述

这样就很方便了,之前我们写链表要去申请节点,现在我们可以这样写:

struct ListNode
{int val;ListNode* next;ListNode(int x):val(x), next(nullptr){}
};int main()
{ListNode* n1 = new ListNode(1);ListNode* n2 = new ListNode(2);ListNode* n3 = new ListNode(3);ListNode* n4 = new ListNode(4);ListNode* n5 = new ListNode(5);n1->next = n2;n2->next = n3;n3->next = n4;n4->next = n5;return 0;
}

在这里插入图片描述
这样就写好了一个链表。
在这里插入图片描述
在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc和free不会调用。

四. operator new和operator delete函数

4.1 operate new和 operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。在c++中new是operator new 加构造函数,delete是operator delete加析构函数
在这里插入图片描述
在这里插入图片描述
通过上述两个全局函数的实现知道,operator new实际上也是通过malloc来申请空间。如果malloc申请成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该应对措施就继续申请,否则就抛异常。operator delete最终通过free释放空间。

五. new和delete的实现原理

5.1 内置类型

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

5.2 自定义类型

new的原理
在这里插入图片描述
1. 调用operator new函数申请空间
2. 在申请的空间上执行构造函数,完成对对象的构造
delete的原理在这里插入图片描述
1. 在空间上执行析构函数,完成对象中的资源清理工作
2. 调用operator delete函数释放对象的空间
new T[N]的原理
在这里插入图片描述
1. 调用operator new[]函数,在operator new函数完成对N个对象空间的申请
2. 在申请的空间上执行N次构造函数
new T[N]可以理解为执行N次new
delete []的原理
在这里插入图片描述

1. 在释放的对象空间上执行N次析构函数,完成N个对象中的资源清理
2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
实际上就是执行N次delete

5.3 使用不匹配

  • 内置类型new和free混用
    在这里插入图片描述
    这里不会报错,因为内置类型调用delete时不需要调用析构函数,只调用了_free_dbg也就是free,因此也不会有内存的泄露。但是不建议这样使用。
  • 自定义类型new和delete混用
    在这里插入图片描述
    这里调用free相比调用delete来说少调用了析构函数,如果A的析构函数有对内存的释放就会存在内存泄露的风险。
  • 内置类型new和delete[] 混用
    在这里插入图片描述
    这里不会有内存泄露的风险,因为new 底层调用的malloc,delete底层调用的free。
  • 自定义类型new[]和delete混用
    在这里插入图片描述
    B类中不存在内存的申请和释放,所以不会内存泄漏。
    但是下面这种情况程序会崩:
    在这里插入图片描述
    这是为什么?
class A
{
public:A(int a = 0): _a(a){cout << "(int a = 0)" << endl;}A(int a ,int b): _a(a),_b(b){cout << "(int a = 0,int b = 0)" << endl;}~A(){cout << "~A():" << endl;}
private:int _a;int _b;
};class B
{
private:int _b1 = 520;int _b2 = 1314;
};

这里A和B的大小都是8个字节
我们还是从汇编来看:
对于B,编译器给了80个空间
在这里插入图片描述
而同样大小,相同个数的A却开了84字节的空间
在这里插入图片描述
在这里插入图片描述
编译器在给A开空间时多开了4个字节用来存储A的元素个数,而返回的地址却没用从多开的4个字节开始返回,而是往后偏移了4个字节,所以会崩。严格来说两者都应该多开4个字节存元素个数,B没有开是因为编译器优化了,因为编译器看到B没有写析构函数而且没有内存的申请和释放,元素个数是给delete[]用的,当使用delete[]时,指针向前偏移四个字节取到元素个数(释放还是在原位置释放),让编译器知道调几次析构函数。B编译器优化到底,不调用析构函数,所以就不存个数。
如果给B写了析构函数,编译器也会开84个字节的空间:
在这里插入图片描述

六. 定位new表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
new(place_address)type 或者new(place_address)type(initializer_list)
place_address必须是一个指针,initializer_list是类型的初始化列表
在这里插入图片描述
上图调用operator new只开了空间并没有初始化,
在这里插入图片描述
在这里插入图片描述
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式对其进行显示调用构造函数进行初始化。

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

结语

以上我们就讲完了C++的内存管理,这里还有一些东西没有讲解,需要后续在讲解。感谢大家的阅读,欢迎大家批评指正!

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

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

相关文章

《计算机原理与系统结构》学习系列——处理器(中)

系列文章目录 目录 流水线数据通路与控制概述5个流水级指令周期与流水级 流水线性能流水线时钟周期的长度T和数量cycles流水线性能 流水线数据通路流水线寄存器流水线分析图形化流水线流水线控制 流水线数据通路与控制 概述 5个流水级 指令周期与流水级 单周期实现中&#x…

鸿蒙网络编程系列40-TLS数字证书查看及验签示例

1. TLS数字证书验签简介 数字证书的验签是网络编程中一个重要的功能&#xff0c;它保证了数字证书的真实性&#xff0c;在此基础上&#xff0c;我们才可以信任该证书&#xff0c;从而信任基于该证书建立的安全通道&#xff0c;所以说&#xff0c;数字证书的验签是通讯安全的基…

路虎裁员,又玩出了新花样。。

大家好&#xff0c;我是程序员面试刷题平台的鸭鸭&#xff01; 最近裁员的新闻已经不少见了&#xff0c;但鸭鸭没想到&#xff0c;公司裁员的花样真是越来越多了。 最近流言中裁员比例超过 50% 的捷豹路虎&#xff0c;听说就专门为裁员开辟了一个快速离职专区&#xff1a;前一…

【Linux】使用<信号量>实现<线程互斥>(思维导图&代码演示&思路解析)

前言 大家好吖&#xff0c;欢迎来到 YY 滴Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

【A股小探-01】股指期货交割日对股指的影响

本文来源于量化小论坛策略分享会板块精华帖&#xff0c;作者为刘世宇&#xff0c;发布于2024年5月3日。 以下为精华帖正文&#xff1a; 01 引言 自踏入 A 股市场以来&#xff0c;笔者注意到了众多所谓的“效应”与“魔咒”&#xff0c;例如黑周四、黑四月、财报季魔咒、节前效…

ios 快捷指令扩展(Intents Extension)简单使用 swift语言

本文介绍使用Xcode15 建立快捷指令的Extension&#xff0c;并描述如何修改快捷指令的IntentHandler&#xff0c;带参数跳转主应用&#xff1b;以及展示多个选项的快捷指令弹框(配置intentdefinition文件)&#xff0c;点击选项带参数跳到主应用的方法 创建快捷指令 快捷指令是…

技术干货|如何巧妙利用数字孪生技术助力口腔保健分析

行业&#xff1a; 口腔医疗 挑战&#xff1a; 传统方法缺乏预测口腔内受力状态&#xff0c;也很难从患者方面获得反馈&#xff0c;因此将口腔扫描、牙齿形状/位置识别和正畸数字模型生成的过程数字化是一个重大机会。 正畸治疗是牙科中最大的类别之一&#xff0c;随着病例的…

星巴克们需要找回节奏

“重返星巴克”需要更多运气。 作者|金豫 编辑|杨舟 国内咖啡市场正上演着一场后浪推前浪的经典剧目。 近期&#xff0c;“太平洋咖啡”传出大规模关店的消息。该品牌在多座城市中仅剩下几家门店&#xff0c;且多数集中在机场。而在2016年前后&#xff0c;太平洋咖啡一度超越…

React 前端框架全面教程:从入门到进阶

React 前端框架全面教程&#xff1a;从入门到进阶 引言 在现代前端开发中&#xff0c;React 作为一款流行的 JavaScript 库&#xff0c;以其组件化、声明式的特性和强大的生态系统&#xff0c;成为了开发者的首选。无论是构建单页应用&#xff08;SPA&#xff09;还是复杂的用…

【力扣 + 牛客 | SQL题 | 每日4题】牛客大厂面试真题W3,W10

1. 牛客大厂面试真题SQLW3&#xff1a;分析客户逾期情况 1.1 题目&#xff1a; 描述 有贷款信息表&#xff1a;loan_tb&#xff08;agreement_id&#xff1a;合同id&#xff0c;customer_id&#xff1a;客户id&#xff0c;loan_amount&#xff1a;贷款金额&#xff0c;pay_a…

在 Windows 中使用 GCC 编译运行 C++

在 Windows 中使用 GCC 编译开发 C 通过 MSYS2 安装 MinGW 工具链 MSYS2&#xff08;Minimal SYStem 2&#xff09;是一个集成了大量的GNU工具链、工具和库的开源软件包集合。它提供了一个类似于 Linux 的shell环境&#xff0c;可以在 Windows 系统中编译和运行许多 Linux 应…

铝基板PCB创建助手

支持在创建元件时创建网表 支持圆形和矩形阵列布局 支持板框信息修改 支持缺口位置修改 支持元件封装预览 支持原理图预览 支持PCB板框和布局预览 支持灯珠方向更改为切向和径向 支持报告输出 支持元件封装选择 铝基板PCB创建助手 V1.0

如何理解全局和局部的规律

再和大家聊的话题是全局和局部的辩证关系。 研究全局和局部的辩证关系&#xff0c;研究的就是做事的方法。 不过这里说的做事的方法不是具体的执行办法&#xff0c;比如这一步应该怎么做&#xff0c;那一步应该怎么做。 而是重在思考&#xff0c;应该先做什么&#xff0c;后…

GPT-Sovits-2-微调模型

1. 大致步骤 上一步整理完数据集后&#xff0c;此步输入数据, 微调2个模型VITS和GPT&#xff0c;位置在 <<1-GPT-SoVITS-tts>>下的<<1B-微调训练>> 页面的两个按钮分别执行两个文件: <./GPT_SoVITS/s2_train.py> 这一步微调VITS的预训练模型…

【LeetCode】两数之和、大数相加

主页&#xff1a;HABUO&#x1f341;主页&#xff1a;HABUO 1.两数之和 题目&#xff1a;给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一…

根据输入的详细地址解析经纬度

摘要&#xff1a; 今天遇到一个需求&#xff1a;就是做客户导入的时候因为导入的客户地址的时候没有经纬度的&#xff0c;但是同步的时候需要经纬度的&#xff0c;所以还是要根据客户提供的详细地址解析出来对应的经纬度&#xff01;回填到对应的经纬度的表单之中进行客户的同步…

【文心智能体 | AI大师工坊】如何使用智能体插件,完成一款旅游类智能体的开发,来体验一下我的智能体『​​​​​​​背包客』

&#x1f680;『背包客』点击前往体验&#xff1a;https://mbd.baidu.com/ma/s/d7RHMlWh 最近参加了百度文心智能体平台AI大师工坊&#x1f389;活动&#xff0c;在这个活动中&#xff0c;我利用文心平台提供的各种插件、大模型等工具&#xff0c;打造了一个工具类的智能体应用…

WPF的触发器(Trigger)

WPF&#xff08;Windows Presentation Foundation&#xff09;是微软.NET框架的一部分&#xff0c;用于构建Windows客户端应用程序。在WPF中&#xff0c;触发器&#xff08;Triggers&#xff09;是一种强大的功能&#xff0c;允许开发者根据控件的状态或属性值来动态改变控件的…

ChatGPT、Python和OpenCV支持下的空天地遥感数据识别与计算——从0基础到15个案例实战应用

在科技飞速发展的时代&#xff0c;遥感数据的精准分析已经成为推动各行业智能决策的关键工具。从无人机监测农田到卫星数据支持气候研究&#xff0c;空天地遥感数据正以前所未有的方式为科研和商业带来深刻变革。然而&#xff0c;对于许多专业人士而言&#xff0c;如何高效地处…

Java中String的length与Oracle数据库中VARCHAR2实际存储长度不一致的问题

目录 一、根本原因 二、解决方案 一、根本原因 Oracle数据库新增数据的时候报如下错误&#xff1a; 先给大家看个小案例&#xff0c;这样更好去理解&#xff0c;下面是一段测试代码&#xff1a; 这里面我分别列举了三种字符串&#xff0c;中文&#xff0c;英文和数字以及两种…