当前位置: 首页 > news >正文

从零开始c++精讲:第三篇——内存管理

文章目录

  • 一、C/C++内存分布
  • 二、C语言中动态内存管理方式:malloc/calloc/realloc/free
  • 三、C++中动态内存管理
  • 四、operator new与operator delete函数
    • 4.1 operator new与operator delete函数(重点)
  • 五、new和delete的实现原理
    • 5.1内置类型
    • 5.2 自定义类型
  • 六、定位new表达式(placement-new)(了解)
  • 七、常见面试题
    • 7.1 malloc/free和new/delete的区别
    • 7.2内存泄漏


一、C/C++内存分布

为什么要有内存区域的划分呢?
因为不同数据有不同的存储需求,各区域满足不同的需求。
在这里插入图片描述

栈(堆栈):一般存放临时用的,比如非静态局部变量/函数参数/返回值等,栈是向下增长的。

:有动态使用的需求,需要的时候你给我,不需要的时候你释放。也就是出了函数作用域,这个变量不会自动销毁,只有我不需要它了才销毁。

数据段(静态区):需要长期使用/整个运行期间都使用的。比如全局数据或静态数据。

代码段(常量区):只读数据不修改。比如可执行代码/只读常量。

内存映射段:是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)

实战演练
在这里插入图片描述

在这里插入图片描述
globalval:是全局变量,在静态区

staticGlobalVal:被static修饰的全局变量,还是在静态区
ps:globalval和staticGlobalVal的区别是在链接属性,globalval可在各个文件可用,staticGlobalVal只在当前文件可用

staticVal:被static修饰的局部变量,还是在静态区
ps:staticGlobalVal可在当前文件用,staticVal只能在所处函数中用。
但是对于生命周期而言,globalval和staticGlobalVal和staticVal是一样的

localVar:一个简单的临时变量,存储在栈上,没啥好说的

num1:虽然是个数组但也是一个临时变量,存储在栈上

char2:这个和num1类似的,都是数组,只不过类型变了。还是存储在栈上

*char2:相当于把指针指向内容解引用,数组上的元素还是在栈内的。

pchar3:是一个指针,定义在栈上。这里的const修饰的是指针指向的内容,不是修饰的指针。

*pchar3:是指针指向的内容,而指针指向的内容是被const修饰的,它是在常量区的
在这里插入图片描述

ptr1:本身是一个栈上的变量,它指向一个堆上的空间

*ptr1:是指针的解引用,指针是指向堆的,解引用就是堆那片空间。

在这里插入图片描述

二、C语言中动态内存管理方式:malloc/calloc/realloc/free

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}

三、C++中动态内存管理

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

int main()
{int* p1 = new int;// 动态申请一个int类型的空间int* p2 = new int[10];//申请10个空间//ps:内置类型默认不初始化,只是单纯开空间//如果想初始化,则单个数据加圆括号,多个数据加花括号,括号里面附上初始化内容int* p3 = new int(1);int* p4 = new int[3]{1,2,3};int* p5 = new int[10]{ 1,2,3 };//初始化的数量不够整个数组大小,则剩下的默认是0delete p1;delete[] p2;delete p3;delete[] p4;delete[] p5;return 0;
}

在这里插入图片描述
ps:c++的new比起c语言的malloc的好处在哪里1?
malloc不方便动态申请自定义对象的初始化问题。
new更方便自定义类型的初始化
在这里插入图片描述

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};int main()
{//malloc不方便动态申请自定义对象的初始化问题A* p1 = new A;//自定义类型,不给参数调用默认构造函数A* p2 = new A(1);//给了参数,调用所给参数的构造函数//初始化多个对象//法一:A aa1(1);A aa2(2);A aa3(3);A* p3 = new A[3]{aa1,aa2,aa3};//法二:匿名对象的方法A* p4 = new A[3]{ A(1),A(2),A(3) };//法三:让编译器自己去调构造函数A* p5 = new A[3]{ 1,2,3 };delete p1;//delete会调用析构函数+释放空间delete p2;delete[] p3;delete[] p4;delete[] p5;return 0;
}

在这里插入图片描述

再举个例子:

struct ListNode
{int _val;ListNode* _next;ListNode(int val):_val(val), _next(nullptr){}
};int main()
{//相比c语言,c++就不用再写什么createNode函数了,你之间用new开空间就行ListNode* n1 = new ListNode(1);ListNode* n1 = new ListNode(2);ListNode* n1 = new ListNode(3);
}

ps:内置类型的对象申请释放,new和malloc除了用法,其他没有区别。但是自定义类型,new可以自己初始化。

对于自定义类型,new和delete会自动开空间,也会自动调构造和析构函数
在这里插入图片描述

class Stack
{
public:Stack(int capacity = 4){cout << "Stack(int capacity=4)" << endl;_a = new int[capacity];_top = 0;_capacity = capacity;}~Stack(){cout << "~Stack()" << endl;delete[] _a;_a = nullptr;_top = 0;_capacity = 0;}
private:int* _a;int _top;int _capacity;
};
int main()
{Stack s1;Stack *p1 = new Stack;//也可以直接开辟一个栈的大小(指针4字节,加两个4字节的int)return 0;
}

你也可以直接new一个Stack大小的空间,然后用p1指向这块空间,内存中情况如下:
p1指向这个对象大小的空间,然后构造函数里的a又new了一块数组。
在这里插入图片描述
而在调delete的时候,是先清理构造函数请求的那块空间,也就是_a指向的空间。然后再释放栈对象(也就是p1指向的空间)。否则你先把栈对象释放了,那栈对面里面的_a指向的空间就找不到了。

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

四、operator new与operator delete函数

4.1 operator new与operator delete函数(重点)

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

operator new 和operator delete库里的全局函数,封装了malloc和free

class Stack
{
public:Stack(int capacity = 4){cout << "Stack(int capacity=4)" << endl;_a = new int[capacity];_top = 0;_capacity = capacity;}~Stack(){cout << "~Stack()" << endl;delete[] _a;_a = nullptr;_top = 0;_capacity = 0;}
private:int* _a;int _top;int _capacity;
};
int main()
{//Stack *p1 = new Stack;//也可以直接开辟一个栈的大小(指针4字节,加两个4字节的int)//delete p1;Stack* p2 = (Stack*)operator new(sizeof(Stack));operator delete(p2);//p2这种用法功能是和C语言的malloc和free是一样的//operator new不会调用构造,operator delete也不会调用析构return 0;
}

在这里插入图片描述
operator new 和operator delete功能上和malloc和free功能上是一样的,但是如果开空间或者销毁空间失败之后,是抛异常的,这是C语言的malloc和free没有的。

另外,如果你是开一个自定义类型的数组,它会自动给你开辟一个sizeof(自定义类型)*数量的空间大小

在这里插入图片描述
后面调用delete,会先调用10次析构函数(会先让p3往前4个字节,找到要析构几次的值,这里是10),再往后就是调用operate delete[ ](ps:operate delete[ ]内部又会调用10次operate 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[]中实际调用operator new函数完成N个对
    象空间的申请
  2. 在申请的空间上执行N次构造函数

delete[]的原理

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

六、定位new表达式(placement-new)(了解)

在这里插入图片描述

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));new(p1)A; // 注意:如果A类的构造函数有参数时,此处需要传参p1->~A();free(p1);A* p2 = (A*)operator new(sizeof(A));new(p2)A(10);p2->~A();operator delete(p2);return 0;
}

七、常见面试题

7.1 malloc/free和new/delete的区别

在这里插入图片描述

7.2内存泄漏

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



相关文章:

  • 计算机毕业设计选题分享-ssm租房小程序42196(赠送源码数据库)JAVA、PHP,node.js,C++、python,大屏数据可视化等
  • esp32-c-简单应用笔记
  • python-基础篇-函数
  • 「实战应用」如何用DHTMLX Gantt构建类似JIRA式的项目路线图(二)
  • 软件测试|使用matplotlib绘制箱型图
  • SpringSecurity(07)——JWT整合
  • react和vue的区别
  • 数字身份所有权:Web3时代用户数据的掌控权
  • EXCEL VBA获取幸运数字号码
  • C++---string类
  • Cinder组件作用
  • HarmonyOS鸿蒙学习基础篇 - 项目目录和文件介绍
  • 计算机基础之总线与I/O总线
  • [Linux] Ubuntu install Miniconda
  • Broadcom交换芯片56620架构
  • hexo+github搭建个人博客
  • 30秒的PHP代码片段(1)数组 - Array
  • CentOS 7 防火墙操作
  • Flex布局到底解决了什么问题
  • java取消线程实例
  • maya建模与骨骼动画快速实现人工鱼
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 阿里云应用高可用服务公测发布
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 机器学习学习笔记一
  • 深度学习入门:10门免费线上课程推荐
  • 通过几道题目学习二叉搜索树
  • AI算硅基生命吗,为什么?
  • (26)4.7 字符函数和字符串函数
  • (C)一些题4
  • (poj1.3.2)1791(构造法模拟)
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (十三)Maven插件解析运行机制
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)ObjectiveC 深浅拷贝学习
  • .Net CF下精确的计时器
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .net 托管代码与非托管代码
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NET/C# 的字符串暂存池
  • .NET6 命令行启动及发布单个Exe文件
  • [ HTML + CSS + Javascript ] 复盘尝试制作 2048 小游戏时遇到的问题
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析
  • [20161214]如何确定dbid.txt
  • [23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution
  • [Android]竖直滑动选择器WheelView的实现
  • [Avalon] Avalon中的Conditional Formatting.
  • [BetterExplained]书写是为了更好的思考(转载)