【C++学习】CC++内存管理

news2025/1/13 10:24:46

目录

一、C&C++内存管理

二、C语言中动态内存管理方式:malloc/calloc/realloc/free

三、C++内存管理方式

3.1 new/delete操作内置类型

3.2 new和delete操作符自定义类型

四、operator new与operator delete函数

4.1 operator new与operator delete函数(重点)

五、new和delete的实现原理

5.1 内置类型

5.2 自定义类型

六、定位new表达式(placement-new)


一、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 区别?

【说明】

  1. 又叫堆栈——非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
  3. 用于程序运行时动态内存分配,堆是可以上增长的。
  4. 数据段——存储全局数据和静态数据。
  5. 代码段——可执行的代码/只读常量。

二、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);
    // 这里需要free(p2)吗?
    free(p3 );
}

malloc的实现原理:Glibc中malloc实现原理

三、C++内存管理方式

        C语言内存管理方式在 C++ 中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++ 又提出了自己的内存管理方式: 通过 new delete 操作符进行动态内存管理。

3.1 new/delete操作内置类型

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

 

注意:申请和释放单个元素的空间,使用newdelete操作符,申请和释放连续的空间,使用new[]delete[]。注意:需要匹配起来使用。

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)); // C
    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 不会。

四、operator newoperator delete函数

4.1 operator newoperator delete函数(重点)

        new和 delete 是用户进行 动态内存申请和释放的操作符 operator new operator delete是 系统提供的全局函数 new 在底层调用 operator new 全局函数来申请空间, delete 在底层通过 operator delete 全局函数来释放空间。
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;
申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
    // try to allocate size bytes
    void *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_FINALLY
     return;
}
/*
free的实现
*/
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)
        通过上述两个全局函数的实现知道,operator new 实际也是通过 malloc 来申请空间 ,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过 free 来释放空间的

五、new和delete的实现原理

5.1 内置类型

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

5.2 自定义类型

  • new的原理
        1. 调用 operator new 函数申请空间。
        2. 在申请的空间上执行构造函数,完成对象的构造。
  • delete的原理
        1. 在空间上执行析构函数,完成对象中资源的清理工作。
        2. 调用 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表达式(placement-new)

定位 new 表达式是在 已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
        new (place_address) type或者 new (place_address) type(initializer-list)
        place_address必须是一个指针, initializer-list 是类型的初始化列表
使用场景:
        定位new 表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new 的定义表达式进行显示调构造函数进行初始化。
class A
{
public:
    A(int a = 0)
        : _a(a)
    {
        cout << "A():" << this << endl;
    }
    ~A()
    {
        cout << "~A():" << this << endl;
    }
private:
    int _a;
};

// 定位new/replacement new
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;
}

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

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

相关文章

【云原生】使用外网Rancher2.5.12在阿里云自建内网K8s 1.20集群

目录 一、目标二、解决方案三、草图四、版本信息五、资源规划六、必要条件七、开始部署1、安装Docker2、安装Rancher3、解析Rancher Server URL域名4、创建K8s集群5、注册K8s集群节点 八、验证 一、目标 在云平台搭建一套高可用的K8s集群 二、解决方案 第一种&#xff1a;使…

横向移动-利用IPC$

环境主机 本次都是在内网自己搭的靶机实验 上线主机&#xff1a;windows2008R2 - 192.168.31.46 需要移动到的主机&#xff1a;windows2012 - 192.168.31.45 实验演示 1.确定域控 通过命令net time /domain&#xff0c;发现存在域 这里我们通过ping来发现域控的ip&#xff0c;…

UGUI Scroll Rect滚动矩形组件

1、概述 当需要在小区域显示占用大量空间的内容时&#xff0c;可以使用Scroll Rect。滚动矩形提供了滚动浏览此内容的功能。 通常&#xff0c;将Scroll Rect与Mask结合在一起以创建滚动视图&#xff0c;在该视图中&#xff0c;只有Scroll Rect内部的可滚动内容可见。它也可以…

类和对象【1】

全文目录 引言&#xff08;初识面向对象&#xff09;类和对象定义类访问限定及封装类定义的两种方式 类实例化与类对象大小this指针 总结 引言&#xff08;初识面向对象&#xff09; C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通…

NSSCTF之Misc篇刷题记录⑩

NSSCTF之Misc篇刷题记录⑩ [CISCN 2022 初赛]ez_usb[SWPUCTF 2021 新生赛]你喜欢osu吗&#xff1f;[SWPUCTF 2021 新生赛]Bill[SWPUCTF 2021 新生赛]二维码不止有二维码[HGAME 2022 week1]好康的流量[红明谷CTF 2022]MissingFile[广东省大学生攻防大赛 2021]这是道签到题[羊城杯…

TOGAF架构开发方法—阶段 F:迁移规划

本章介绍迁移规划;也就是说&#xff0c;如何通过最终确定一个 详细的实施和迁移计划。 一、目标 F阶段的目标是&#xff1a; 最终确定架构路线图以及支持实施和迁移计划确保实施和迁移计划与企业的管理和实施方法相协调 企业整体变更组合的变化确保关键利益相关者了解工作包和…

【什么是蜂窝移动网络】

从 DataReportal 2021 年 1 月的统计数据来看&#xff0c;全球 78 亿人口中&#xff0c;有 52 亿手机用户&#xff0c;46 亿互联网用户。能够接入网络的设备越来越多&#xff0c;体量越来越大&#xff0c;不知道你有没有好奇过&#xff0c;这样一个庞大的世界是如何被构造出来的…

【Linux】指令(下)

⭐博客主页&#xff1a;️CS semi主页 ⭐欢迎关注&#xff1a;点赞收藏留言 ⭐系列专栏&#xff1a;Linux ⭐代码仓库&#xff1a;Linux 家人们更新不易&#xff0c;你们的点赞和关注对我而言十分重要&#xff0c;友友们麻烦多多点赞&#xff0b;关注&#xff0c;你们的支持是我…

论文阅读:Multimodal Graph Transformer for Multimodal Question Answering

文章目录 论文链接摘要1 contribution3 Multimodal Graph Transformer3.1 Background on Transformers3.2 Framework overview 框架概述3.3 Multimodal graph construction多模态图的构建Text graphSemantic graphDense region graph Graph-involved quasi-attention 总结 论文…

【AIGC提示工程 - MidJourney教程:一】“Midjourney AI“是什么,为何众人皆谈?

关注元壤教育公众号系统学习AIGC提示工程课程。 更多AIGC好博客&#xff0c;请移步访问AIGC博客派 Midjourney AI是一个极富创造性的工具&#xff0c;它能够帮助用户通过指令创建图像。这些图像是基于用户的想象力而创造的。 在本文中&#xff0c;我们将详细了解Midjourney AI。…

软件测试面试面对史上最难求职季,会哪些测试技能更容易拿到offer?

在一线大厂&#xff0c;没有测试这个岗位&#xff0c;只有测开这个岗位。这几年&#xff0c;各互联网大厂技术高速更新迭代&#xff0c;软件测试行业也 如果你在中小型公司&#xff0c;普通的测试工程师20K差不多到极限了&#xff0c;薪资想再进一步提升很困难。而在阿里巴巴P…

【AIGC提示工程 - MidJourney教程:二】《MidJourney参数大全指南:实现最佳图像输出的关键》

关注元壤教育公众号系统学习AIGC提示工程课程。 更多AIGC好博客&#xff0c;请移步访问AIGC博客派 这篇文章介绍了不同的MidJourney参数和提示词&#xff0c;帮助你创建你选择的图像。探索如何使用不同的风格和参数进行操作。 如果你使用Midjourney应用&#xff0c;你就知道提示…

NetSuite SuiteQL 内建函数

之前写过一篇文章介绍SutieQL Query Tool&#xff0c;今天继续挖掘一下SuiteQL的价值。 NetSuite SuiteQL Query Tool_netsuite好用吗_毛岩喆的博客-CSDN博客这是一个非常好的NetSuite数据查询工具&#xff0c;免费、强大&#xff01;所以忍不住安利给大家。首先介绍一下背景&…

Redis系列--redis持久化

一、为什么需要持久化 redis本身运行时数据保存在内存中&#xff0c;如果不进行持久化&#xff0c;那么在redis出现非正常原因宕机或者关闭redis的进程或者关闭计算机后数据肯定被会操作系统从内存中清掉。当然&#xff0c;redis本身默认采用了一种持久化方式&#xff0c;即RD…

11.Kafka系列之Stream实践

Kafka Streams是一个基于Apache Kafka的处理库&#xff0c;可以用于实现高效、可扩展的实时数据处理应用程序。它是一个轻量级的库&#xff0c;允许你在Java和Scala中创建和运行流处理应用程序&#xff0c;这些应用程序可以读取输入流&#xff0c;执行各种数据转换&#xff0c;…

MyBatis的配置案例

Mybatis中Map的使用 如果需要所有的代码&#xff0c;可以看我上一篇 在接口中定义 int addUser1(Map<String,Object> map); 插入语句 <insert id"addUser1">insert into user(id,name,pwd) values (#{userid},#{username},#{userPwd})</insert> …

Vue3-黑马(十)

目录&#xff1a; &#xff08;1&#xff09;vue3-antdv-全局提示与校验 &#xff08;2&#xff09;vue3-进阶-router-入门 &#xff08;3&#xff09;vue3-进阶-router-动态导入-嵌套路由-重定向 &#xff08;1&#xff09;vue3-antdv-全局提示与校验 当用户新增修改&…

redis(11)

一)基于Set集合实现点赞功能: 在我们的博客表当中&#xff0c;每一篇博客信息都有一个like字段&#xff0c;表示点赞的数量 需求: 1)同一个用户只能点赞一次&#xff0c;再次进行点赞则会被取消&#xff1b; 2)如果当前用户已经点赞过了&#xff0c;那么点赞按钮高亮显示&…

传输层:UDP协议

传输层中有两个重要的协议&#xff1a;TCP协议和UDP协议。 本博文分享的是UDP协议&#xff0c;本文将从UDP的协议格式、UDP的特定以及其缓冲区入手。 传输层 传输层的作用是负责数据能够从发送端传输到接收端&#xff0c;主要是传输策略。 端口号 端口号标识的是一个主机上进…

【AIGC提示工程 - Midjourney教程:三】如何利用Midjourney AI创作一幅杰出的艺术作品?

关注元壤教育公众号系统学习AIGC提示工程课程。 更多AIGC好博客&#xff0c;请移步访问AIGC博客派 要在Discord上使用Midjourney机器人&#xff0c;您需要输入一个指令。指令能帮助您创建图片、修改默认设置、监控用户信息以及执行其他有用的操作。如果想要生成一张图片&#x…