【C++】拆分详解 - 内存管理

文章目录

  • 前言
  • 一、C/C++内存分布
  • 二、C语言中动态内存管理方式:malloc/calloc/realloc/free
  • 三、C++内存管理方式
    •   3.1 new/delete操作内置类型
    •   3.2 new和delete操作自定义类型
    •   3.3 operator new与operator delete函数
  • 四、new和delete的实现原理
    •   4.1 内置类型
    •   4.2 自定义类型
      •    4.2.1  底层原理分析
      •    4.2.2  示例(栈)
  • 五、 扩展思考
    •   5.1 delete[] 为什么不需要写释放个数?
    •   5.2 构造个数与析构个数不匹配
  • 六、malloc/free和new/delete的区别
  • 总结


前言

本文在C语言基本内存管理知识的基础上,介绍了C++的动态内存管理的不同之处,旨在帮助读者复习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);
}//题目
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) = ____;3. sizeof 和 strlen 区别?

在这里插入图片描述

在这里插入图片描述

  • 易错
char2[] = "abcd" //开辟一个数组,将字符串abcd赋值拷贝进去
const char* pchar3 = “abcd” //创建一个指针指向常量字符串"abcd"
*char2 //解引用数组名,拿到的是首元素地址,不是拿到常量字符串

二、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);// 2.这里需要free(p2)吗?不需要,理由如下free(p3);
}
malloc 动态开辟
calloc 动态开辟 + 初始化为0
realloc 动态调整 //原空间内存充足则原地调整//不足则异地调整,另外开辟一片空间将原数据拷贝过去且自动销毁原空间

三、C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理(分别对应malloc,free),往后我们将很少使用到C的内存管理方法。

  3.1 new/delete操作内置类型

void Test()
{// 动态申请一个int类型的空间int* ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 = new int(10);// 动态申请3个int类型的空间int* ptr6 = new int[3];delete ptr4;delete ptr5;delete[] ptr6;
}

在这里插入图片描述

申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。(思考:如果不匹配会发生什么?后续在 5.2 处我们进行解答)

  3.2 new和delete操作自定义类型

class A
{
public:A(int a = 0) : _a(a){cout << "A():" << this << endl; //标识调用了构造函数}~A(){cout << "~A():" << this << endl; //标识调用了析构函数}private:int _a;
};int main()
{// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);free(p1);delete p2;// 内置类型是几乎是一样的int* p3 = (int*)malloc(sizeof(int)); int* p4 = new int;free(p3);delete p4;A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[10];free(p5);delete[] p6;return 0;
}

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

  3.3 operator new与operator delete函数

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

  • 【operator new 就是对 malloc 的封装,相当于 malloc + 报错功能(抛异常)】
  • 【operator delete 就是对 free 的封装】

下面我们来粗略看一下VS中的汇编代码

 /*operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{void* 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);
}/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void* pUserData)
{_CrtMemBlockHeader* pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK);  __TRYpHead = pHdr(pUserData);_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg(pUserData, pHead->nBlockUse); //调用_free_dbg ,实际就是free的底层__FINALLY_munlock(_HEAP_LOCK);__END_TRY_FINALLYreturn;
}/*
free的实现
*/
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

四、new和delete的实现原理

  4.1 内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL

  4.2 自定义类型

   4.2.1  底层原理分析

  • new的原理(operator new + 构造函数)
  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造
  • delete的原理(operator delete + 析构函数)
  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间

在这里插入图片描述

  • new T[N]的原理(operator new []+ 构造函数)
  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对
    象空间的申请
  2. 在申请的空间上执行N次构造函数
  • delete[]的原理(operator delete[] + 析构函数)
  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释
    放空间

在这里插入图片描述

   4.2.2  示例(栈)

在这里插入图片描述

五、 扩展思考

  5.1 delete[] 为什么不需要写释放个数?

new[] 开空间时会格外开辟一个对应类型大小的空间,用以存储开辟的个数(语法上delete[] 中不需要写个数,但实际上编译器要用,从多开的空间中拿)

在这里插入图片描述

  5.2 构造个数与析构个数不匹配

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}//手动实现析构,会报错//未实现,可能会报错(取决于编译器是否优化)~A(){cout << "~A():" << this << endl;}
private:int _a;
};// 记住,一定要匹配使用,不匹配结果是不确定的
int main()
{int* p1 = new int[10];delete p1;A* p2 = new A[10];delete p2;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在释放空间前会调用析构函数完成空间中资源的清理

总结

本文介绍了C++的动态内存管理的常用知识,旨在帮助读者复习C,快速过渡到C++

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

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

相关文章

【微服务】SpringCloud之Feign远程调用

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 …

Solo 开发者周刊 (第10期):Sora 之后,谁是被遗忘的?谁又是被仰望的?

这里会整合 Solo 社区每周推广内容、产品模块或活动投稿&#xff0c;每周五发布。在这期周刊中&#xff0c;我们将深入探讨开源软件产品的开发旅程&#xff0c;分享来自一线独立开发者的经验和见解。本杂志开源&#xff0c;欢迎投稿。 好文推荐 Solo 社区 x 机器之心-再谈复现 …

如何利用HubSpot 出海CRM实现精准海外客户定位与拓展?

在当今全球化的商业环境中&#xff0c;企业寻求海外市场的拓展已成为增长的重要策略。然而&#xff0c;海外市场的复杂性和多样性为企业带来了巨大的挑战。为了有效地定位和拓展海外客户&#xff0c;许多企业选择了HubSpot 出海CRM作为他们的营销和销售管理工具。今天运营坛将带…

Android Glide

1.引入glide implementation com.github.bumptech.glide:glide:4.14.2 // Skip this if you dont want to use integration libraries or configure Glide. annotationProcessor com.github.bumptech.glide:compiler:4.14.2 //Glide 注解处理器 2.AndroidManifest.xml 中添加…

HarmonyOS NEXT应用开发之LocalStorage:页面级UI状态存储

LocalStorage是页面级的UI状态存储&#xff0c;通过Entry装饰器接收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage支持UIAbility实例内多个页面间状态共享。 本文仅介绍LocalStorage使用场景和相关的装饰器&#xff1a;LocalStorageProp和LocalStorageLink。 说…

购买代码签名证书时需提供哪些认证资料?

在软件开发与发布过程中&#xff0c;确保软件的可靠性和完整性至关重要&#xff0c;为此购买代码签名证书是必不可少的环节。然而&#xff0c;许多开发者对于购买该证书所需的具体材料并不十分清楚。下面就为大家详细介绍购买代码签名证书所需材料&#xff0c;助您更好地筹备和…

文心一言指令词宝典之自媒体篇

作者&#xff1a;哈哥撩编程&#xff08;视频号、抖音、公众号同名&#xff09; 新星计划全栈领域优秀创作者博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 &#x1f3c6; 推荐专栏&#xff1a; &#x1f3c5;…

考研||考公||就业||其他?-------愿不再犹豫

大三下了&#xff0c;现在已经开学一个多月了&#xff0c;在上个学期的时候陆陆续续吧周围有的行动早的人已经开始准备考研了&#xff0c;当然这只是下小部分人吧&#xff0c;也有一部分人是寒假可能就开始了&#xff0c;更多的则是开学的时候&#xff0c;我的直观感受是图书馆…

【Easy云盘 | 第二篇】后端统一设计思想

文章目录 4.1后端统一设计思想4.1.1后端统一返回格式对象4.1.2后端统一响应状态码4.1.3后端统一异常处理类4.1.4StringUtils类4.1.5 RedisUtils类 4.1后端统一设计思想 4.1.1后端统一返回格式对象 com.easypan.entity.vo.ResponseVO Data public class ResponseVO<T> …

Sharding

Sharding操作 什么是ShardingSharding-JDBC一、引入maven依赖 &#xff08;sharding-jdbc-spring-boot-starter&#xff09;二、水平分表操作&#xff08;一个库多个相同结构表&#xff09;其他的maven依赖版本 &#xff08;shardingsphere-jdbc-core-spring-boot-starter&…

vmware 中的Ubuntu系统虚拟机忘记root密码强制重置操作

忘记密码情况下&#xff0c;vmware虚拟机重置Ubuntu的root密码 在企业使用的vmware ESXI中重置Ubuntu系统root密码 1-本地电脑安装个人版的vmware workstation&#xff0c;目的&#xff1a;vmware ESXI自带的远程控制台无法输入指定的键盘按键&#xff0c;需要借助外部的远程辅…

【ELK】搭建elk日志平台(使用docker-compose),并接入springboot项目

1、环境搭建 前提条件&#xff1a;请自行安装docker以及docker-compose环境 version: 3 services:elasticsearch:image: elasticsearch:7.14.0container_name: elasticsearchports:- "9200:9200"- "9300:9300"environment:# 以单一节点模式启动discovery…

java之static详细总结

static也叫静态&#xff0c;可以修饰成员变量、成员方法。 成员变量 按照有无static分为两种&#xff1a; 类变量&#xff1a;static修饰&#xff0c;属于类&#xff0c;与类一起加载一次&#xff0c;在内存中只有一份&#xff0c;会被类的全部对象共享实例变量&#xff08;…

Elastic AI Assistant for Observability 和 Microsoft Azure OpenAI 入门

作者&#xff1a;来自 Elastic Jonathan Simon 最近&#xff0c;Elastic 宣布 AI 观测助手现已正式向所有 Elastic 用户开放。该 AI 观测助手为 Elastic 观测提供了一种新工具&#xff0c;提供了大型语言模型&#xff08;LLM&#xff09;连接的聊天和上下文洞察&#xff0c;以解…

JavaWeb入门——Web前端概述及HTML,CSS语言基本使用

前言&#xff1a; java基础已经学完&#xff0c;开始学习javaWeb相关的内容&#xff0c;整理下笔记&#xff0c;打好基础&#xff0c;daydayup!!! Web Web&#xff1a;全球广域网&#xff0c;也称万维网&#xff08;www World Wide Web&#xff09;&#xff0c;能够通过浏览器访…

Hadoop MapReduce

MapReduce分为两个阶段&#xff0c;分为Map阶段和Reduce阶段&#xff0c;可以自定义map函数和reduce函数&#xff0c; map函数的输入是行在文件的字节偏移量&#xff0c;value是文件的一行数据。 reduce函数的输入是key和对应key的value组&#xff0c;然后reduce函数可以对这…

加州大学欧文分校英语基础语法专项课程01:Word Forms and Simple Present Tense 学习笔记

Word Forms and Simple Present Tense Course Certificate 本文是学习Coursera上 Word Forms and Simple Present Tense 这门课程的学习笔记。 文章目录 Word Forms and Simple Present TenseWeek 01: Introduction & BE VerbLearning Objectives Word FormsWord Forms (P…

C++ 【桥接模式】

简单介绍 桥接模式属于 结构型模式 | 可将一个大类或一系列紧密相关的类拆分 为抽象和实现两个独立的层次结构&#xff0c; 从而能在开发时分别使用。 聚合关系&#xff1a;两个类处于不同的层次&#xff0c;强调了一个整体/局部的关系,当汽车对象销毁时&#xff0c;轮胎对象…

基于单片机光伏太阳能跟踪系统设计

**单片机设计介绍&#xff0c;基于单片机光伏太阳能跟踪系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机光伏太阳能跟踪系统的设计&#xff0c;旨在通过单片机技术实现对光伏太阳能设备的自动跟踪&#xff0c;以提高太阳…

寄快递便宜啦!德邦、韵达、京东、圆通等八大品牌快递五折起!

低价服务&#xff0c;为你的快递需求保驾护航。 一、与全网主流快递合作&#xff0c;信赖与质量的共同见证 是一家整合快递、物流、及国际快递资源的综合快递服务平台&#xff0c;通过人工智能比价系统&#xff0c;为个人及企业客户提供市面上优惠的快递价格&#xff0c;目前…