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.rhkb.cn/news/272562.html

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

相关文章

代码随想录训练营第41天 | 动态规划:01背包理论基础、动态规划:01背包理论基础(滚动数组)、LeetCode 416.分割等和子集

动态规划&#xff1a;01背包理论基础 文章讲解&#xff1a;代码随想录(programmercarl.com) 视频讲解&#xff1a;带你学透0-1背包问题&#xff01;_哔哩哔哩_bilibili 动态规划&#xff1a;01背包理论基础&#xff08;滚动数组&#xff09; 文章讲解&#xff1a;代码随想录(…

支付宝开放平台证书验签生成签名接入方式的操作流程之公钥证书,密钥证书的生成

#小李子9479# 调用支付宝接口的安全验证方式均使用sign_type为RSA2的方式&#xff0c;有两种 1。密钥模式&#xff1a;应用公钥、应用私钥、平台公钥生成签名和验签方式 2。证书模式&#xff1a;支付宝根证书、支付宝公钥证书、应用公钥证书、应用私钥&#xff0c;采用RSA20…

Solidity Uniswap V2 价格预言机

预言机是连接区块链与链下服务的桥梁&#xff0c;这样就可以从智能合约中查询现实世界的数据。Chainlink 是最大的oracle网络之一&#xff0c;创建于 2017 年&#xff0c;如今已成为许多 DeFi 应用的重要组成部分。https://github.com/XuHugo/solidityproject Uniswap 虽然是链…

【❤️算法笔记❤️】-每日一刷-19、删除链表的倒数第 N个结点

文章目录 题目思路解答 题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]示例 3&…

迷不迷糊?前后端、三层架构和MVC傻傻分不清

现在的项目都讲究前后端分离&#xff0c;那到底什么是前后端&#xff0c;前后端和以前的MVC以及三层架构啥关系呢&#xff1f;今天就这个问题展开一下&#xff0c;方面后面的学习&#xff0c;因为前面讲的jsp、servlet和javabean根据实例&#xff0c;基本上有一个框架的理解了&…

Ubuntu下使用DAPLink(OpenOCD)

目录 1. 下载OpenOCD源代码 2. 编译代码 2.1 运行bootstrap 2.2 安装关联库 2.3 运行./configure 2.4 运行make 2.5 运行sudo make install 3. 烧录程序 3.1 挂起MCU 3.2 写入镜像 3.3 校验镜像 通过OpenOCD实现&#xff0c;在Ubuntu18 64bit下验证。 1. 下载OpenOC…

人力资源社会保障部教育部关于印发《关于深化中小学教师职称制度改革的指导意见》的通知

人力资源社会保障部、教育部印发 关于《深化中小学教师职称制度改革的指导意见》的通知 人社部发[2015]79号 各省、自治区、直辖市及新疆生产建设兵团人力资源社会保障厅&#xff08;局&#xff09;、教育部门&#xff08;教委、教育局&#xff09;&#xff1a; 为深化教育…

机器学习第29周周报 Beyond Dropout

文章目录 week29 Beyond Dropout摘要Abstract一、泛化理论二、文献阅读1. 题目2. abstract3. 网络架构3.1 特征图失真3.2 失真优化 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 全连接层实验4.3.2 卷积网络上的实验 4.4 结论 小结参考文献 week29 Beyond Dropout …

【C++专栏】C++入门 | 函数重载、引用、内联函数

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;C专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ C入门 | 函数重载、引用、内联函数 文章编号&#xff1a;C入门 / 02 文…

sizeof辨析——二维数组(超级详细)

二维数组加sizeof的知识如果基础不扎实&#xff0c;上面的代码恐怕很难区分&#xff0c;这篇文章就深度解析一下有关问题 我们在分析之前&#xff0c;要提及一些基础的前提知识 前提知识&#xff1a; 一&#xff1a; &数组名 和 sizeof&#xff08;数组名&#xff09;这…

【算法沉淀】最长回文子串

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

每日OJ题_路径dp①_力扣62. 不同路径

目录 力扣62. 不同路径 解析代码 力扣62. 不同路径 62. 不同路径 难度 中等 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标…

视频可回溯系统技术方案vue3+ts+tegg+mysql+redis+oss

一、 项目背景 保险、基金、银行等众多行业在做技术平台时都会需要一种能够准确了解用户操作行为的方式方法。诸如通过埋点、平台监控、视频可回溯等&#xff0c;通过技术手段&#xff0c;保存用户操作轨迹&#xff0c;以此规范安全销售、平台健康检查、出现纠纷时可追溯、问题…

chrome插件开发的几种展现页面形式,3分钟看完

想要开发一个chrome浏览器插件&#xff0c;还是很有必要清楚插件都可以在哪些地方显示出来的&#xff0c;比如只想在pop页面弹出&#xff0c;还是添加右键菜单&#xff0c;还是提示桌面通知&#xff1f;还是在哪里展示&#xff1f;有哪些展示方式等 browserAction(浏览器右上角…

免费下载Corel Video Studio 2024-轻松创建令人惊叹的视频!

免费下载Corel Video Studio 2024-轻松创建令人惊叹的视频&#xff01; Corel Video Studio 2024免费下载Keygen 你厌倦了在视频编辑软件上花大钱吗&#xff1f;别再看了&#xff01;我们为您提供了完美的解决方案——Corel Video Studio 2024。最棒的部分是什么&#xff1f;…

分享MDN前端结构化技能、实践指南、学习资源

前言 MDN课程为成为一名成功的前端开发人员提供了一个结构化的基本技能和实践指南&#xff0c;以及推荐的学习资源。 先看下让人不得不服的书《宝宝的网页设计》&#xff08;套装共3册&#xff09; 宝宝的HTML、宝宝的CSS、宝宝的JavaScript 全球首套中英文宝宝编程启蒙书&a…

计算机网络 八股

计算机网络体系结构 OSI&#xff1a;物理层、数据链路层、网络层、运输层、会话层、表示层、应用层

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Gauge)

数据量规图表组件&#xff0c;用于将数据展示为环形图表。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 可以包含单个子组件。 说明&#xff1a; 建议使用文本组件构建当前数值文本和辅…

【xv6操作系统】xv6 启动过程分析

一、调试用到的汇编代码 为了方便&#xff0c; Makefile 会创建.asm 文件&#xff0c;可以通过它来定位究竟是哪个指令导致了 bug。 可以看到&#xff0c; kernel 从 80000000 地址处开始执行&#xff0c;第二列为相应指令&#xff08;如 auipc&#xff09; 的 16 进制表示&a…

缩放算法优化步骤详解

添加链接描述 背景 假设数据存放在在unsigned char* m_pData 里面&#xff0c;宽和高分别是&#xff1a;m_nDataWidth m_nDataHeight 给定缩放比例&#xff1a;fXZoom fYZoom&#xff0c;返回缩放后的unsigned char* dataZoom 这里采用最简单的缩放算法即&#xff1a; 根据比…