Cpp内存管理(7)

文章目录

  • 前言
  • 一、C/C++内存区域划分
  • 二、C/C++动态内存管理
    • C语言动态内存管理
    • C++动态内存管理
      • 对于内置类型
      • 对于自定义类型
  • 三、new和delete的底层实现
  • 四、new和delete的实现原理
  • 五、定位new
  • 六、malloc/free和new/delete的区别
  • 总结


前言

  软件开发过程中,内存管理的重要性不言而喻
  因此我们有必要了解一下C++中关于内存管理的一些特性

C++对内存的自由度使其获得了更高的性能,以及更高的难度。
内存泄漏往往是每个C++学习者绕不开的错误, 而内存管理的水平高低也能看出一个编程者的能力


一、C/C++内存区域划分

我们先来看一下以下代码:

int globalVar = 1;           // 全局变量
static int staticGlobalVar = 1; // 静态全局变量void Test() {static int staticVar = 1; // 静态局部变量int localVar = 1;         // 局部变量int num1[10] = {1, 2, 3, 4}; // 局部数组char char2[] = "abcd";    // 字符数组const char* pChar3 = "abcd"; // 字符指针常量int* ptr1 = (int*)malloc(sizeof(int) * 4);  // 动态分配内存int* ptr2 = (int*)calloc(4, sizeof(int));  // 动态分配并初始化int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4); // 重新分配内存free(ptr1); // 释放内存free(ptr3);
}

你能说出globalVal、staticGlobalVar、staticVar、localVar、num1、*num1存在哪里吗?

在C++中,程序的内存区域从低地址到高地址划分如下:

  1. 代码段:存储可执行程序的代码和只读常量
  2. 数据段:存储已初始化的全局变量和静态变量
  3. 堆:用于程序运行时动态内存分配,从低地址向高地址增长
  4. 栈:又叫堆栈,存储非静态局部变量/函数参数和返回值等,从高地址向低地址增长

图形语言如下:
在这里插入图片描述

  我们倒回去看,我挑几个比较有意思的来细讲,你也可以重点关注一下,staticVar、char2、*char2、pChar3、*pChar3、*ptr2分别存储在哪里

变量名存储段
staticVar静态局部变量,存在数据段
char2字符指针变量,存在栈
*char2数组元素,存在栈,不是存在代码段,因为不是只读!!!
pChar3局部指针变量,存在栈
*pChar3只读变量,存在代码段
*ptr2动态分配的内存,存在堆

哦,对了,关于上面所说的“栈是向下增长的,而堆是向上增长的”,
简单来说就是在栈区开辟空间,先开辟的空间地址较高,而在堆区开辟空间,先开辟的空间地址较低
你可以通过以下代码来验证一下:

// 实在验证不出来就算了,这个跟编译器等环境关系很大
#include <iostream>
using namespace std;
int main()
{// 栈区开辟空间,先开辟的空间地址高int a = 10;int b = 20;cout << &a << endl;cout << &b << endl;// 堆区开辟空间,先开辟的空间地址低// 具体实现中,关于堆我们可能会验证失败// 你可以试着想一下这是为什么?int* c = (int*)malloc(sizeof(int)* 10);cout << c << endl;// free(c);加了这行,发现两个输出相同// 说明在堆区,后开辟的空间也有可能位于前面某一被释放的空间位置int* d = (int*)malloc(sizeof(int)* 10);cout << d << endl;return 0;
}

二、C/C++动态内存管理

C语言动态内存管理

  我们来回顾一下几种用于动态分配内存的函数:malloc、calloc、realloc 和 free,这些函数用于在程序运行时动态地分配和释放内存

malloc:用于分配指定大小的内存块,内存中的内容未初始化
calloc:类似于 malloc,但会将内存初始化为零。它的参数为元素的数量和每个元素的大小
realloc:用于调整之前分配的内存块的大小,如果新大小大于原大小,可能会移动内存块的位置

来个示例代码:

int* ptr1 = (int*)malloc(sizeof(int) * 4);  // 分配4个int类型大小的内存块
int* ptr2 = (int*)calloc(4, sizeof(int));   // 分配并初始化4个int类型大小的内存块
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4); // 重新分配内存free(ptr1);
free(pter2);
free(ptr3);

C++动态内存管理

  C++继承了C语言的内存管理方式,并在此基础上引入了newdelete操作符,提供更方便的动态内存管理机制,这并不奇怪,因为C++本来就是祖师爷觉得C麻烦,在其基础上发展而来的

new 和 delete 适用于对象的动态内存分配,并且会自动调用构造函数和析构函数,这很重要

对于内置类型

  对于内置类型,其实 new 和 delete 在底层上多大的差别,只是使用的规则要有所区分

以下相对应内容等价

	// 动态申请单个int类型的空间int* p1 = new int; //申请delete p1; //销毁// 动态申请单个int类型的空间int* p2 = (int*)malloc(sizeof(int)); //申请free(p2); //销毁// 动态申请10个int类型的空间int* p3 = new int[10]; //申请delete[] p3; //销毁// 动态申请10个int类型的空间int* p4 = (int*)malloc(sizeof(int)* 10); //申请free(p4); //销毁// 动态申请单个int类型的空间并初始化为10int* p5 = new int(10); //申请 + 赋值delete p5; //销毁// 动态申请一个int类型的空间并初始化为10int* p6 = (int*)malloc(sizeof(int)); //申请*p6 = 10; //赋值free(p6); //销毁// 动态申请10个int类型的空间并初始化为0到9int* p7 = new int[10]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; //申请 + 赋值delete[] p7; //销毁// 动态申请10个int类型的空间并初始化为0到9int* p8 = (int*)malloc(sizeof(int)* 10); //申请for (int i = 0; i < 10; i++) //赋值{p8[i] = i;}free(p8); //销毁

申请和释放单个元素的空间,使用new和delete操作符;申请和释放连续的空间,使用new[ ]和delete[ ]

对于自定义类型

 new会调用构造函数,delete会调用析构函数,而malloc和free不会,原理下文再来解释

三、new和delete的底层实现

 new和delete并不是函数,而是用户进行动态内存申请和释放的操作符

但是其底层还是需要调用函数
且虽然函数名中带operator,但并不是重载函数,具有很强的误导性!!!

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

我们来看一下operator new 和 operator free 的底层实现:

void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid* p;while ((p = malloc(size)) == 0) // 注意这里,就是mallocif (_callnewh(size) == 0){// report no memory// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}return (p);
}void operator delete(void* pUserData)
{_CrtMemBlockHeader* pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK);  /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg(pUserData, pHead->nBlockUse); // 注意这里,就是free__FINALLY_munlock(_HEAP_LOCK);  /* release other threads */__END_TRY_FINALLYreturn;
}

看不懂?看不懂就对了,我也看不懂,但是你注意一下我两个特意的注释点

 可以看出 operator new 实际上也是通过 malloc 来申请空间的,如果 malloc 申请空间成功就直接返回,如果失败则执行用户提供的应对措施,如果用户提供该措施则继续申请空间,否则抛出异常

其实,这也叫封装,就像引用的底层也是用指针的方式实现的

在这里插入图片描述

四、new和delete的实现原理

内置类型无非就是包一下,加个抛出异常,而对于自定义类,就复杂了

一、new的原理
  调用operator new函数申请空间,在申请的空间上执行构造函数,完成对象的构造

二、delete的原理
  在空间上执行析构函数,完成对象中资源的清理工作,调用operator delete函数释放对象的空间

三、new T[N]的原理
  调用operator new[]函数,而operator new[]函数实际上又会调用operator new函数完成N个T类型对象的空间申请,在申请的空间上执行N次构造函数

四、delete[]的原理
  在空间上执行N次析构函数,完成N个对象的资源清理调用operator delete[]函数,而operator delete[]函数又会调用operator delete函数来释放空间

五、定位new

  定位new表达式用于在已分配的原始内存空间中调用构造函数初始化一个对象

使用格式
new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表

  其实这个内容,你可以暂时做个了解,因为这个一般搭配内存池使用,这又牵扯到一个概念叫做池化技术,而内存池分配出的内存没有初始化,所以如果是自定义类型的对象,就需要使用定位new表达式进行显示调用构造函数进行初始化

#include <iostream>
using namespace std;class A
{
public:A(int a = 0) // 构造函数 :_a(a){}~A() // 析构函数{}
private:int _a;
};int main()
{// new(place_address)type 形式A* p1 = (A*)malloc(sizeof(A));new(p1)A;// new(place_address)type(initializer-list) 形式A* p2 = (A*)malloc(sizeof(A));new(p2)A(2021);// 析构函数也可以显示调用// 这就是为什么只有定位new,没有定位delete的缘故p1->~A();p2->~A();return 0;
}

六、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在释放空间前会调用析构函数完成
    空间中资源的清理释放 (这是原理,希望你对此有个深刻的印象)

总结

  哈,本节内容还是蛮轻松惬意的,至少跟类和对象比起来是这样
  那么现在,我们来接着往下看模板
  相信我,这会更有意思!!!

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

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

相关文章

关于 mybatis-plus-boot-starter 与 mybatis-spring-boot-starter 的错误

不是知道你是否 出现过这样的错误 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): 经过各种度娘&#xff0c;无非就是让你检查三种情况 情况一&#xff1a;mapper.xml没有按照传统的maven架构进行放置 情况二&#xff1a;mybatis的配置信…

c++ day06

类的栈 实现 #include <iostream>using namespace std;class Stack { private:static const size_t MAX 100; // 定义固定容量int data[MAX]; // 存储栈元素的数组size_t len; // 当前栈的大小public:// 构造函数Stack() : len…

【Python从入门到进阶】65、Pandas如何批量拆分与合并Excel文件

接上篇《64、Pandas如何实现数据的Concat合并》 上一篇我们学习了Pandas如何实现数据的Concat合并&#xff0c;本篇我们来继续学习Pandas如何批量拆分与合并Excel文件。 一、引言 在当今数据驱动的时代&#xff0c;Excel文件作为数据处理和分析的基石&#xff0c;扮演着不可或…

Selenium4.0实现自动搜索功能

01.Selenium4.0实现搜索功能 1.安装Selenium及查看Selenium版本 pip install selenium pip show seleniumfrom selenium import webdriver from chromedriver_py import binary_path import time from selenium.webdriver.common.by import By from selenium.webdriver.commo…

(补充)3DMAX初级小白班第三课:创建物体+物体材质编辑

1.可以点这里来改变材质颜色&#xff08;但是通过材质编辑器给了材质以后就只能在这里改线框颜色&#xff09;。但一般就是用灰色材质和黑色线框 2.材质编辑器快捷键为m 右键可更改个数&#xff0c;最多24个 将材质指定选定对象 如何把材质编辑器面板改成旧版 按f10 改成扫描…

《微信小程序实战(3) · 推广海报制作》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

火车票有电子发票吗?没纸质火车票怎么报销?

火车票有电子发票吗&#xff1f; 火车票、高铁票目前没有电子发票&#xff0c;但是现在已经实行电子客票&#xff0c;车票即购票证件&#xff0c;乘车时&#xff0c;只需购票证件原件&#xff08;如身份证、护照、临时身份证等&#xff09;即可乘车。 没纸质火车票怎么报销&am…

英伟达发布NVLM 1.0:屠榜多模态任务,纯文本性能逆势提升

前沿科技速递&#x1f680; 随着文本大模型的发展&#xff0c;解码器架构已经成为文本处理任务的标准。然而&#xff0c;现有的多模态大模型架构却尚未统一&#xff0c;不同模型在选择 LLM 主干、视觉编码器以及训练数据上存在较大差异&#xff0c;且无法直接进行对比研究。为了…

凤凰模拟器V6中无人机如何设置“有头模式”

凤凰模拟器是一款专为航模新手设计的飞行模拟器&#xff0c;它能够模拟大疆无人机、各种穿越机、固定翼等多种飞行器&#xff0c;提供逼真的飞行体验。该软件的操作简单易懂&#xff0c;适合新手练习使用。 一般来说&#xff0c;打开凤凰模拟器&#xff0c;选择好机型&#xf…

vscode 配置django

创建运行环境 使用pip安装Django&#xff1a;pip install django。 创建一个新的Django项目&#xff1a;django-admin startproject myproject。 打开VSCode&#xff0c;并在项目文件夹中打开终端。 在VSCode中安装Python扩展&#xff08;如果尚未安装&#xff09;。 在项…

鸿蒙HarmonyOS开发:一次开发,多端部署(界面级)天气应用案例

文章目录 一、布局简介二、典型布局场景三、侧边栏 SideBarContainer1、子组件2、属性3、事件 四、案例 天气应用1、UX设计2、实现分析3、主页整体实现4、具体代码 五、运行效果 一、布局简介 布局可以分为自适应布局和响应式布局&#xff0c;二者的介绍如下表所示。 名称简介…

Golang | Leetcode Golang题解之第421题数组中两个数的最大异或值

题目&#xff1a; 题解&#xff1a; const highBit 30type trie struct {left, right *trie }func (t *trie) add(num int) {cur : tfor i : highBit; i > 0; i-- {bit : num >> i & 1if bit 0 {if cur.left nil {cur.left &trie{}}cur cur.left} else …

leetcode-189:轮转数组

给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4…

前端框架对比与选择

&#x1f916; 作者简介&#xff1a;水煮白菜王 &#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧✍。 感谢支持&#x1f495;&#x1f495;&#x1f495; 目…

详细分析SpringMvc中HandlerInterceptor拦截器的基本知识(附Demo)

目录 前言1. 基本知识2. Demo3. 实战解析 前言 对于Java的基本知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09; 1. 基本知识 HandlerInter…

量化交易四大邪术之三:春去花还在

网络相传亚洲有四大邪术&#xff0c;日本化妆&#xff0c;韩国整容&#xff0c;泰国变X&#xff0c;Z国PS。 这些都是让人在颜值上看起来很美&#xff0c;类似地&#xff0c;在量化交易领域&#xff0c;也有四大邪术能让净值曲线看起来很美&#xff0c;之前已经说了“般若波罗蜜…

CSS clip-path 属性的使用

今天记录一个css属性clip-path&#xff0c;首先介绍下这个属性。 clip-path 是CSS中的一个神奇属性&#xff0c;它能够让你像魔术师一样&#xff0c;对网页元素施展“裁剪魔法”——只展示元素的一部分&#xff0c;隐藏其余部分。想象一下&#xff0c;不用依赖图片编辑软件&am…

Python--类【详细教程】

类的介绍 面向对象编程&#xff08;object-oriented programming&#xff0c;OOP&#xff09;是最有效的软件编写方法之⼀。在面向对象编程中&#xff0c;你编写表示现实世界中的事物的类&#xff08;class&#xff09;&#xff0c;并基于这些类来创建对象&#xff08;object&…

C语言 | Leetcode C语言题解之第436题寻找右区间

题目&#xff1a; 题解&#xff1a; typedef struct {int start;int index; } Node;int cmp(const void *pa, const void *pb) {return ((Node *)pa)->start - ((Node *)pb)->start; }int* findRightInterval(int** intervals, int intervalsSize, int* intervalsColSiz…

四川财谷通信息技术有限公司抖音小店强势引领电商

在数字经济蓬勃发展的今天&#xff0c;短视频与直播电商已成为推动消费增长的重要引擎&#xff0c;而抖音平台更是以其庞大的用户基础、精准的算法推荐和创新的商业模式&#xff0c;成为了众多商家争相入驻的蓝海市场。在这片充满活力的电商沃土上&#xff0c;四川财谷通信息技…