【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;前一…

C#运算符与表达式详解

在C#编程中&#xff0c;运算符和表达式是构建复杂逻辑和处理数据的关键元素。以下是对C#运算符与表达式的详细解析&#xff1a; 一、运算符 运算符是一种特殊的符号&#xff0c;用于执行各种数学、逻辑和其他操作。C#中的运算符可以分为以下几类&#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;例如黑周四、黑四月、财报季魔咒、节前效…

K8S nginx pod结合cronJob实现日志按天切割 —— 筑梦之路

前言 nginx的官方镜像都是把日志重定向到标准输出&#xff0c;如果没有特别需求&#xff0c;已经能满足大多数的使用。 这里我主要对官方镜像进行改造&#xff0c;添加logrotate&#xff0c;结合cronJob来实现nginx日志的自动轮转&#xff0c;以方便排查故障问题。 编写Dock…

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

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

GPT论文整理提示词

论文阅读 指令1:粗读论文 请你阅读并理解这篇文献&#xff0c;然后将该篇文章的标题作为一级标题&#xff0c;将摘要和各个大标题作为二级标题&#xff0c;将小标题作为三级标题&#xff0c;将小标题下每一部分内容作为四级标题&#xff0c;给我以markdown的语言输出中文的翻…

【回溯算法】(第七篇)

目录 ⼦集&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 找出所有⼦集的异或总和再求和&#xff08;easy&#xff09; 题目解析 讲解算法原理 编写代码 ⼦集&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;Le…

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

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

ubuntu 挂载 新 硬盘 ext3

ubuntu 挂载 新 硬盘 在Ubuntu中使用新的硬盘并格式化为ext3文件系统&#xff0c;你需要执行以下步骤&#xff1a; 插入硬盘并确认系统已识别。 确定硬盘的设备名称&#xff0c;例如 /dev/sdb。 使用mkfs.ext3命令格式化硬盘为ext3文件系统。 以下是具体的命令&#xff1a…

Spring 设计模式之装饰器模式

Spring 设计模式之装饰器模式 装饰器模式用到的场景具体的java例子&#xff1a; 装饰器模式 装饰器模式允许我们在不修改原始类&#xff08;即被装饰对象&#xff09;的情况下&#xff0c;动态地向对象添加新的行为或修改现有行为。 用到的场景 存在一个原始类&#xff0c;在…

星巴克们需要找回节奏

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

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

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

【日志】网络传输协议TCP/UDP/HTTP // unity泛型类单例模式

2024.10.23 【力扣刷题】 暂无 【数据结构】 暂无 【其他】 TCP&#xff08;传输控制协议&#xff09;&#xff08;长连接&#xff09;&#xff1a; TCP 是一种面向连接的、可靠的协议&#xff0c;它通过三次握手建立连接&#xff0c;确保数据的可靠传输。 第一次是客户端向服…

【力扣 + 牛客 | 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

Nginx 配置基于IP 地址的 Web 服务器

Nginx 配置基于IP 地址的 Web 服务器 1.配置网卡 nmcli connection modify ipv4.address 192.168.232.130/24 ipv4.gateway 192.168.232.2 ipv4.dns 192.168.232.2 ipv4.method manual connection.autoconnect yes 2.添加ip地址 nmcli connection modify ens160 ipv4.address…