【C++语言】动态内存管理

在这里插入图片描述


文章目录

  • 前言
  • 内存管理
    • 数据存储位置
    • C语言动态内存管理方式
    • C++动态内存管理方式:new/delete
    • operator new与operator delete函数
    • new和delete的实现原理
    • 定位new表达式(了解)
    • 常见面试题
  • 总结
  • C++语言系列学习目录


前言

本章要介绍的是动态内存管理:

  • 我们的定义的变量,储存位置在哪?
  • C动态内存管理方式:malloc/calloc/realloc/free
  • C++动态内存管理方式:new/delete
  • operator new与operator delete函数
  • new和delete的实现原理
  • 定位new表达式

内存管理

数据存储位置

不妨先来看看以下代码:看自己能否分清楚?

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);}1. 选择题:
选项: A.栈  B.堆  C.数据段(静态区)  D.代码段(常量区)globalVar在哪里?____   staticGlobalVar在哪里?____staticVar在哪里?____   localVar在哪里?____num1 在哪里?____char2在哪里?____      *char2在哪里?___  pChar3在哪里?____     *pChar3在哪里?____ptr1在哪里?____       *ptr1在哪里?____2. 填空题:
sizeof(num1) = ____;
sizeof(char2) = ____;      strlen(char2) = ____;
sizeof(pChar3) = ____;     strlen(pChar3) = ____;
sizeof(ptr1) = ____;

答案如下:
在这里插入图片描述
如果有困难的话,就可以往下看了。

需要存储的一些数据它的存储方式如下:
在这里插入图片描述

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);}

C语言动态内存管理方式

C语言的动态内存管理方式,我们其实已经了解了:malloc/calloc/realloc/free。就不过多介绍了,通过一个面试题来测试下自己的掌握情况: 【面试题】malloc/calloc/realloc的区别?

C++动态内存管理方式:new/delete

  1. 内置类型:
void Test1()
{//malloc~free// 动态申请一个int类型的空间int* ptr1 = (int*)malloc(sizeof(int));//动态申请一个int类型的空间并初始化为10int* ptr2= (int*)malloc(sizeof(int));if (ptr2 != NULL)*ptr2 = 10;// 动态申请10个int类型的空间int* ptr3 = (int*)malloc(sizeof(int)*10);free(ptr1);free(ptr2);free(ptr3);//new~delete// 动态申请一个int类型的空间int* ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 = new int(10);// 动态申请10个int类型的空间int* ptr6 = new int[3];//动态申请4个int类型的空间并初始化为1,2,3,4int* ptr7=new int[4]{1,2,3,4};delete ptr4;delete ptr5;delete[] ptr6;delete[] ptr7;
}

在这里插入图片描述
其实不难发现malloc和new在内置类型上都只是开辟空间,差别其实不大,最多就是多写几行代码。

  1. 自定义类型:
class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
void Test2()
{//new~delete除了开辟空间,还会调用自定义类型的构造和析构函数。A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);free(p1);delete p2;
}

在这里插入图片描述
从上方反汇编代码,我们可以清楚的看到,new调用了构造函数而delete调用了析构函数。而malloc和free并不会,这也是new和malloc的最大区别。

operator new与operator delete函数

那为什么有这样的区别呢?C语言过渡到C++,malloc到new,这会不会有什么关联呢?答案是肯定的。

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

在这里插入图片描述
我们进入封装内容看下:
在这里插入图片描述

不信,我们来看看operator new代码呗:

//operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
//失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid* p;while ((p = malloc(size)) == 0)if (_callnewh(size) == 0){// report no memory// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
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);__FINALLY_munlock(_HEAP_LOCK);  /* release other threads */__END_TRY_FINALLYreturn;
}
/*
free的实现
*/
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的

new和delete的实现原理

  • 整体过程:
    在这里插入图片描述
    new的实现:
  • 开辟空间:调用operator new 开辟空间,开辟的是自定义类型大小的空间;
  • 构造函数:主要是申请资源,也就是_array的空间申请;
    在这里插入图片描述
    delete的实现:
  • 析构函数:先释放_array申请的资源;
  • 释放空间:然后调用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表达式(了解)

注意:这已经不是new了,而是new这个关键字的一个用法

new可以显示调用构造函数和析构函数,以下代码为定位new来模拟new和delete的实现过程。

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;
}

常见面试题

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在释放空间前会调用析构函数完成 空间中资源的清理

总结

本节主要是介绍空间内的存储,以及一些管理动态内存的方法。最重要的是new和delete的用法以及它的原理。


C++语言系列学习目录

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

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

相关文章

ORACLE ODA一体机存储节点电源故障的分析处理

近期&#xff0c;某用户的ORACLE ODA一体机在例行机房巡检时出现亮黄灯告警&#xff1b;用户反馈次问题后我们立刻通过远程方式&#xff0c;登陆ODA的控制台进行查看&#xff1b; 对于ODA一体机&#xff08;2个计算节点1个存储节点&#xff09;&#xff0c;计算节点可以通过il…

nginx 发布静态资源

一. nginx 发布静态资源 在nginx中nginx.conf配置文件中添加内容如下&#xff1a; server {listen 90;server_name localhost;# 配置静态资源文件&#xff0c;就可以访问了location / {root /home/fooie-shop;index index.html;}# 配置音频和图片资源location /imoo…

深入了解 npm:Node.js 包管理工具详解

文章目录 一、npm 基本概念1.1 什么是 npm&#xff1f;1.2 package.json 文件 二、npm 常用命令2.1 初始化项目2.2 安装依赖2.2.1 安装单个包2.2.2 全局安装包2.2.3 安装开发依赖 2.3 移除依赖2.4 更新依赖2.5 查看已安装的包2.6 发布包 三、npm 高级用法3.1 使用 npm scripts3…

数据结构之二叉树详解[1]

在前面我们介绍了堆和二叉树的基本概念后&#xff0c;本篇文章将带领大家深入学习链式二叉树。 1.预备知识 2.二叉树结点的创建 3.二叉树的遍历 3.1前序遍历 3.2中序遍历 3.3 后序遍历 4.统计二叉树的结点个数 5.二叉树叶子结点的个数 6.二叉树第k层的结点个数 7.总结 …

589.N叉树的前序遍历

刷算法题&#xff1a; 第一遍&#xff1a;1.看5分钟&#xff0c;没思路看题解 2.通过题解改进自己的解法&#xff0c;并且要写每行的注释以及自己的思路。 3.思考自己做到了题解的哪一步&#xff0c;下次怎么才能做对(总结方法) 4.整理到自己的自媒体平台。 5.再刷重复的类…

高级个人主页

高级个人主页 效果图部分代码领取源码下期更新预报 效果图 部分代码 <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" name"viewport" content"widthdevice-width, initial-scale1, maximum-scale1, use…

数据驱动测试在接口测试和网站测试中的应用

什么是数据驱动测试 据驱动测试是一种测试方法&#xff0c;其中测试数据和测试逻辑是分开的&#xff0c;测试数据被存储在外部源中&#xff08;如Excel表格、JSON文件、数据库等&#xff09;&#xff0c;测试逻辑则独立于测试数据。在测试过程中&#xff0c;测试数据被读取并传…

代码随想录算法训练营第五十三天

今天同事说他要离职啦&#xff0c;还挣挺多的&#xff0c;我也慢慢努力吧&#xff01;&#xff01; 儿子似乎有点斜颈&#xff0c;还好不是很大的病&#xff0c;儿子也开始面对人生的苦难啦。都好好加油生活&#xff01; 1143.最长公共子序列 二维可以理解一点。 class Solut…

用面向对象的思想编写实时嵌入式C程序

实时嵌入式系统的软件一般由C语言编写&#xff0c;程序结构基本上都是这样的&#xff1a; // 主程序 int main(void) {init(); // 初始化while(1){tick(); // 业务逻辑}return 0; }// 计时器 static unsigned int g_timer_tick_cnt 0; // 时钟中断回调 void isr_time…

[c++]多态的分析

多态详细解读 多态的概念多态的构成条件 接口继承和实现继承: 多态的原理:动态绑定和静态绑定 多继承中的虚函数表 多态的概念 -通俗的来说&#xff1a;当不同的对象去完成某同一行为时&#xff0c;会产生不同的状态。 多态的构成条件 必须通过基类的指针或者引用调用虚函数1虚…

超级简单的地图操作工具开发可疑应急,地图画点,画线,画区域,获取地图经纬度等

使用echars的地图画点,画线,画区域,获取地图经纬度等 解压密码:10086007 地图也是用临时的bmap.js和china.js纯离线二选一 一共就这么多文件 画点,画线,画区域 点击地图获取经纬度-打印到控制台,这样就能渲染航迹,多变形,结合其他算法算圆等等操作 下载资源:https://download…

Databend 开源周报第 144 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 了解 Databend …

Redis-详解(基础)

文章目录 什么是Redis&#xff1f;用Redis的特点&#xff1f;用Redis可以实现哪些功能&#xff1f;Redis的常用数据类型有哪些?Redis的常用框架有哪些?本篇小结 更多相关内容可查看 什么是Redis&#xff1f; Redis&#xff08;Remote DictionaryServer&#xff09;是一个开源…

【AI学习】对指令微调(instruction tuning)的理解

前面对微调&#xff08;Fine-tuning&#xff09;的学习中&#xff0c;提到指令微调。当时&#xff0c;不清楚何为指令微调&#xff0c;也一直没来得及仔细学习。 什么是指令微调&#xff1f;LLM经过预训练后&#xff0c;通过指令微调提升模型的指令遵循能力。所谓指令&#xf…

uniapp怎么使用jsx

安装vitejs/plugin-vue-jsx npm install vitejs/plugin-vue-jsx -Dvite.config.js配置 import { defineConfig } from "vite"; import uni from "dcloudio/vite-plugin-uni"; import vueJsx from vitejs/plugin-vue-jsxexport default defineConfig({plu…

全方位入门git-慕课网 笔记

目录 【上传github忽略某些文件】【配置用户名和邮箱】【想要删除不需要的文件时如何进行操作】【想要给文件重命名如何操作】【想要移动文件到其他位置时如何操作】【文件有变化时&#xff0c;如何查看前后变化】【操作失误的情况下如何实现一键还原】【不再追踪时如何实现撤销…

区块链 | NFT 水印:Review on Watermarking Techniques(一)

&#x1f34d;原文&#xff1a;Review on Watermarking Techniques Aiming Authentication of Digital Image Artistic Works Minted as NFTs into Blockchains 1 应用于 NFT 的水印技术 常见的水印技术类型可以分为&#xff1a; 可见 v i s i b l e \mathsf{visible} visi…

项目9-网页聊天室1(注册+Bycrpt加密)

1.准备工作 1.1.前端页面展示 1.2 数据库的建立 我们通过注册页面&#xff0c;考虑如何设计用户表数据库。 用户id&#xff0c;userId用户名&#xff0c;唯一&#xff0c;username用户密码&#xff0c;password&#xff08;包括密码和确认密码ensurePssword【数据库没有该字段…

【全开源】酷柚易汛ERP 源码部署/售后更新/上线维护

一款基于FastAdminThinkPHPLayui开发的ERP管理系统&#xff0c;帮助中小企业实现ERP管理规范化&#xff0c;此系统能为你解决五大方面的经营问题&#xff1a;1.采购管理 2.销售管理 3.仓库管理 4.资金管理 5.生产管理&#xff0c;适用于&#xff1a;服装鞋帽、化妆品、机械机电…

openssl 生成证书步骤

本地测试RSA非对称加密功能时&#xff0c;需要用到签名证书。本文记录作者使用openssl本地生成证书的步骤&#xff0c;并没有深入研究openssl&#xff0c;难免会有错误&#xff0c;欢迎指出&#xff01;&#xff01;&#xff01; 生成证书标准流程&#xff1a; 1、生成私钥&am…