C++内存管理篇

文章目录

  • 1. C/C++内存分布
  • 2. C++中的内存管理方式
  • 3. operator new和operator delete函数
  • 4. new和delete的实现原理
  • 5. 定位new表达式(placement-new)

1. C/C++内存分布


C语言中,为了方便管理内存空间,将内存分成了不同的区域,每个区域管理不同的数据

C++中,保持着跟C语言一样的内存区域划分

在这里插入图片描述

int main() 
{int a = 0; const int b = 1; //很多人有个误区,认为被const修饰的变量在常量区 //实际上,被const修饰的变量叫做常变量,它本质还是个变量,只不过有了常属性 //因此b是在栈区上的 cout << &a << endl; cout << &b << endl; char arr1[] = "abcd"; const char* arr2 = "abcd"; arr1[0]++; //arr2[0]++; ((char*)arr2)[0]++; //即使将arr2强转成char*,程序在运行的过程中也会崩溃,暴力修改常量区的数据 return 0; 
}

2. C++中的内存管理方式


C++语言中,我们用malloc/calloc/realloc/free函数进行内存的开辟和释放,对内存进行管理

C++中,这些函数依然可用,但在使用上是比较麻烦的;因此C++中增加了new和delete操作符,使用这两个操作符进行内存的管理

  • C语言使用的是函数进行内存管理
  • C++中new和delete是操作符,不是函数
int main()
{//申请一个int类型的空间int* p1 = new int;//申请一个int类型的空间并初始化int* p2 = new int(1);//申请一个数组int* p3 = new int[10];//C++11支持//申请一个数据并初始化int* p4 = new int[10]{ 1,2,3 };delete p1;delete p2;delete[] p3;delete[] p4;return 0;
}

相比于C语言中利用函数管理内存,C++中的管理内存方式有哪些好处:

  1. 用法更加简洁

  2. 可以控制初始化

  3. 对于自定义类型,开辟空间+自动调用对应的构造函数

    struct ListNode
    {
    public:ListNode(int val):_val(val), _next(nullptr){}int _val;ListNode* _next;
    };int main()
    {ListNode* node1 = new ListNode(1);ListNode* node2 = new ListNode(2);ListNode* node3 = new ListNode(3);delete node1;delete node2;delete node3;return 0;
    }
    
  4. new失败了以后抛异常,不需要手动检查

    void Func2()
    {int n = 1;while (1){int* p = new int[1024 * 1024 * 10];cout << n << "->" << p << endl;n++;}
    }int main()
    {try{Func2();}catch (const exception& e){cout << e.what() << endl;}return 0;
    }
    
  5. 对于自定义类型,申请空间时,new会调用对应的构造函数;delete会调用对应的析构函数

    class A
    {
    public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}private:int _a;
    };
int main()
{A* p1 = new A(1);//调用一次构造delete p1;//调用一次析构A* p2 = new A[10];//调用十次构造delete[] p2;//调用十次析构return 0;
}

3. operator new和operator delete函数


看到operator+操作符,第一直觉会以为这是对new和delete操作符的重载函数,但其实它们不是重载函数

实际上,这两个函数是系统提供的全局函数

在底层,new通过调用operator new函数来实现申请空间;delete通过调用operator delete函数来时间空间的释放

operator new函数最终通过malloc函数申请空间,申请成功则返回,否则抛异常

operator delete函数最终通过free函数释放空间

可以看到,new和delete的最底层还是使用的malloc和free函数,只不过是对它进行了一系列封装

4. new和delete的实现原理


在这里插入图片描述

对于内置类型:

  • 两者的效果差不多,不同的是new在申请空间失败时抛异常,malloc则返回NULL

对于自定义类型:

  • new会调用operator new函数申请空间,再在申请的空间上调用构造函数
  • delete会调用析构函数完成对象中的资源清理,再调用operator delete释放对象的空间
  • new T[n]会调用operator new[]函数,operator new[]函数会调用operator new函数申请n个对象的空间
  • delete[]会调用n次析构函数,完成n个对象中资源的清理,再调用operator delete[]函数,operator delete[]安徽念书会调用operator delete函数,释放n个对象的空间
class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}private:int _a;
};int main()
{A* p3 = new A[10];delete[] p3;return 0;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

当然,不是所有情况都会留出一块空间存放对象个数

内置类型不需要析构,也就不会留出空间

没有显示定义析构函数的自定义类型也不会留出空间,因为没有显示定义析构函数,就认为不需要析构函数释放对象中的资源

new和delete使用时一定要对应,否则可能会出现不确定的结果

int main()
{// 程序能运行,但不推荐int* p1 = new int(1);delete[] p1;//error 正确的写法:delete p1// 若A显示定义析构函数,程序陷入无限调用析构的死循环中// 若A没有显示定义析构函数,程序能运行,但不推荐A* p2 = new A(1);delete[] p2;//error 正确的写法:delete p2// 程序能运行,但不推荐int* p3 = new int[10];delete p3;//error 正确的写法:delete[] p3// 若A显示定义析构函数,程序报错,原因是释放的位置错了// 若A没有显示定义析构函数,程序能运行,但不推荐A* p4 = new A[10];delete p4;//error 正确的写法:delete[] p4return 0;
}
// C语言创建不带哨兵位的链表
typedef int DataType;struct ListNode
{DataType val;struct ListNode* next;
};struct ListNode* CreateNewNode(DataType val)
{struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));if (newNode == NULL){perror("malloc fail");exit(-1);}newNode->next = NULL;newNode->val = val;return newNode;
}struct ListNode* CreateList(int n)
{struct ListNode* head = CreateNewNode(-1);struct ListNode* tail = head;for (int i = 1; i <= n; i++){struct ListNode* temp = CreateNewNode(i);tail->next = temp;tail = tail->next;}struct ListNode* cur = head->next;free(head);return cur;
}int main()
{struct ListNode* head = CreateList(5);return 0;
}struct ListNode
{
public:ListNode(int val):_val(val),_next(nullptr){}int _val;ListNode* _next;
};// C++创建不带哨兵位的链表
ListNode* CreateList(int n)
{ListNode head(-1);ListNode* tail = &head;int val = 0;printf("请依次输入值:>");for (int i = 1; i <= n; i++){cin >> val;ListNode* newNode = new ListNode(val);tail->_next = newNode;tail = tail->_next;}return head._next;
}int main()
{ListNode* list = CreateList(5);return 0;
}

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


在某些场景下,我们向内存申请的空间没有初始化,比如向内存池申请的空间,如果是自定义类型的对象,我们可以使用new的定义表达式进行显示调用构造函数进行初始化

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}private:int _a;
};int main()
{A* p1 = (A*)operator new(sizeof(A));new(p1)A(1);p1->~A();operator delete(p1);return 0;
}

malloc/free和new/delete的区别:

  • 共同点:都是从堆上申请空间,需要自己手动释放空间

  • 不同点:

    用法上:

    1. malloc/free是函数;new/delete是操作符
    2. malloc申请的空间不会初始化;new会初始化
    3. malloc申请空间时,需要手动计算空间大小;new只需加上空间类型即可,想创建多个对象,只需在[]里加上对象的个数
    4. malloc的返回值为void*,需要做强转处理;new的返回值就是空间类型,不需要处理
    5. malloc申请空间失败时返回NULL,因此使用时必须先判空;new不需要,但new需要捕获异常

    底层特性上:

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

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

相关文章

【数据分享】2013-2022年全国范围逐月CO栅格数据(免费获取)

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2000-2022年全国范围逐月的PM2.5栅格数据和2013-2022年全国范围逐月SO2栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;。 本次我们给大家带来的是2013-2022年全国范围的逐月的CO栅格…

【微信小程序】基本语法

目录 一、列表渲染&#xff08;包括wx:for改变默认&#xff09; 二、事件冒泡和事件捕获 三、生命周期 一、列表渲染&#xff08;包括wx:for改变默认&#xff09; 1、列表渲染(wx-for、block 改变默认wx:for item等) <view> {{msg}} </view> //渲染跟普通vu…

jupyter notebook 调整深色背景与单元格宽度与自动换行

# 安装jupyter主题 pip install jupyterthemes # 列举主题 jt -l # 设置主题 jt -t chesterish设置宽度 打开users 当前用户目录下的custom.css文件 写入.container { width:80% !important; } 即可 设置自动换行 查找创建这个目录以及文件notebook.json 写入配置 “li…

DualSPHysics使用FlowTool工具进行后处理,定义的粒子全在domains外,解决办法

可以知道DualSPHysics官方给了后处理工具使用的示例&#xff0c;如下就是官方给的案例&#xff0c;使用FlowTool工具可以计算出在两个实体domain内的粒子数。 然而我自己也定义了2个domains&#xff0c;但是计算出来Tank1和Tank2里边的粒子数一直是空的&#xff0c;粒子全部在…

保姆级讲解字符串函数(上篇)

目录 字符分类函数 导图 函数介绍 1.getchar 2. isupper 和 islower 字符转换函数&#xff1a;&#xff08;toupper , tolower&#xff09; 与 putchar 字符串函数 导图 string函数的使用和模拟实现 string的使用 求字符串长度 字符串的比较 string函数的模拟实现…

王道机试C++第 4 章 字符串:字符串内容续写几个小程序 Day30

统计字符 习题描述 统计一个给定字符串中指定的字符出现的次数。 输入描述&#xff1a; 测试输入包含若干测试用例&#xff0c;每个测试用例包含2行&#xff0c;第1行为一个长度不超过5的字符串&#xff0c;第2行为一个长度不超过80的字符串。注意这里的字符串包含空格&…

Sora的盈利新视角:从共创经济到产业赋能

随着科技的进步&#xff0c;人工智能和机器学习技术正逐渐成为推动经济增长的新动力。在这样的背景下&#xff0c;Sora作为一款先进的AI视频生成工具&#xff0c;其盈利路径和产业影响也呈现出新的特点。本文将从共创经济和产业赋能的角度&#xff0c;探讨Sora的盈利新路径以及…

kamailio转发电话到目的地,目的返回失败时再转给其他IP

按图中这样测试&#xff1a; A---->kamailio------->B B返回480等失败错误码&#xff08;非200 OK&#xff09;&#xff0c;能进入failure_route[TOVOICEMAIL]&#xff0c;但是t_relay_to_udp执行失败。 好吧&#xff0c;说是&#xff1a;在 failure_route 中处理的是…

苍穹外卖-day01

苍穹外卖-day01 目录 苍穹外卖-day01课程内容1. 软件开发整体介绍1.1 软件开发流程1.2 角色分工1.3 软件环境 2. 苍穹外卖项目介绍2.1 项目介绍2.2 产品原型2.3 技术选型 3. 开发环境搭建3.1 前端环境搭建3.2 后端环境搭建3.2.1 熟悉项目结构3.2.2 Git版本控制3.2.3 数据库环境…

【考研数学】129高分学姐二战经验+资料分享

21年数学三87分 22年数学三129分 可以说这两年该踩的雷我都踩了、该做的题我都做了。 进来看看是什么使我突然醒悟让我数学提分40多分的叭。 李林的880题我也做过&#xff0c;先来说说这本书的优缺点以及适用人群吧。 习题优点 李林老师的880题难度适中&#xff0c;很贴近…

【视频转码】基于ZLMediakit的视频转码技术概述

一、概述 zlmediakit pro版本支持基于ffmpeg的转码能力&#xff0c;在开源版本强大功能的基础上&#xff0c;新增支持如下能力&#xff1a; 1、音视频间任意转码(包括h265/h264/opus/g711/aac等)。2、基于配置文件的转码&#xff0c;支持设置比特率&#xff0c;codec类型等参…

LeetCode-Hot100

哈希 1.两数之和&#xff1a; 给定一个整数数组nums和一个整数目标值target&#xff0c;请你再该数组中找出和为目标值target的那两个整数&#xff0c;并返回它们的数组下标。 思路&#xff1a;暴力解法是使用两层循环来遍历每一个数&#xff0c;然后找出两数之和等于target的…

Unity的PICO项目基础环境搭建笔记(调试与构建应用篇)

文章目录 前言一、为设备开启开发者模式1、开启PICO VR一体机。前往设置>通用>关于本机>软件版本号2、一直点击 软件版本号 &#xff0c;直到出现 开发者 选项3、进入 开发者模式&#xff0c;打开 USB调试&#xff0c;选择 文件传输 二、实时预览应用场景1、下载PC端的…

2024年新手视频剪辑软件推荐-6款视频剪辑软件测评

视频剪辑软件推荐 premiere premiere 直达地址:各大软件网站 说到底,还是得专业的来,虽然很多人觉得他是收费的,但是你懂的,想要免费总是会有办法的.别的不说,剪辑这块,我还是很认可这个软件,虽然我现在还是刚入门. 剪映 剪映 抖音官方推出的一款手机视频编辑剪辑应用,提供切割…

go切片实现原理

近日一直在学习golang,已经产出如下博客一篇 GO闭包实现原理(汇编级讲解) 引言 最近在使用go语言的切片时,出现了一些意料之外的情况,遂查询相关文档学习后写下此篇博客 正文 首先,我们思考,go在通过函数传递一个切片时,是通过引用传递的吗,还是通过值传递的呢(答案将会很…

Transformer之多角度解读

Transformer 文章目录 Transformer  &#x1f449;引言&#x1f48e; 一、 自注意力机制 &#xff1a; 主要用于 长距离依赖捕捉和转换序列二、 Encoder&#xff1a;2.1 多头注意力机制&#xff1a;2.2 残差连接&#xff1a; 三、 Decoder&#xff1a;3.1 Decoder 多头注意力…

hive sql无法停止

排查流程 hive任务停止是调用org.apache.hive.jdbc.HiveStatement的close()方法实现的 其底层是委托给org.apache.hive.service.cli.thrift.TCLIService.Iface客户端实例来实现。 同时&#xff0c;通过JDK动态代理为其织入了synchronized同步机制&#xff1a;其底层是委托给…

申请公众号上限是多少

一般可以申请多少个公众号&#xff1f;公众号申请限额在过去几年内的经历了很多变化。对公众号申请限额进行调整是出于多种原因&#xff0c;确保公众号内容的质量和合规性。企业公众号的申请数量从50个到5个最后到2个&#xff0c;对于新媒体公司来说&#xff0c;这导致做不了公…

【XMU学科实践二】豆瓣爬虫实践

文章目录 分析豆瓣阅读网站具体步骤构造headersBeautiful soup中的定位函数find() 、find_all() 完整爬虫代码 叠甲&#xff1a;仅供学习。。 XMU的小朋友实在不会了可以参考我的思路&#xff0c;但还是建议自己敲一遍哈。 学科实践二还是挺有意思的&#xff01; 分析豆瓣阅读网…

什么是jwt

jwt是JSON Web Token&#xff0c;由3部分构成&#xff1a; 头部Header&#xff1a;头部包含了两部分&#xff0c;token 类型和采用的加密算法&#xff08;可为none&#xff0c;后端应限制加密算法&#xff0c;不以这里为准&#xff09;。 载荷Payload&#xff1a;这部分才是重要…