1.Cpp中的内存分配

  • 了解动态内存在C++中是如何工作的是成为一名合格的C++程序员必不可少的。C++程序中的内存分为两个部分:

    • 栈:在函数内部声明的所有变量都将占用栈内存。
    • 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存
  • 很多时候,在无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。在C++中,可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即new运算符。如果不再需要动态分配的内存空间,可以使用delete运算符,删除之前由new运算符分配的内存。

2.new和delete运算符

  • 下面是使用new运算符来为任意的数据类型动态分配内存的通用语法:

        new 数据类型;
    
  • 上面的数据类型可以是包括数组在内的任意内置的数据类型,也可以是包括类或结构在内的用户自定义的任何数据类型。先来看下内置的数据类型。例如,可以定义一个指向double类型的指针,然后请求内存,该内存在执行时被分配。可以按照下面的语句使用new运算符来完成这点:
        double *ptr = NULL;  // 初始化为null的指针ptr = new double;  // 为变量请求内存
    
  • 如果自由存储区已被用完,可能无法成功分配内存。所以建议检查new运算符是否返回NULL指针,并采取以下适当的操作:
        double *ptr = NULL;if(!(ptr == new double){cout << "Error: out of memory.\n";exit(1);}
    
  • malloc()函数在C语言中就出现了,在C++中仍然存在,但建议尽量不要使用malloc()函数。new与malloc()函数相比,主要的优点是:new不只是分配了内存,还创建了对象!在任何时候,当觉得某个已经动态分配内存的变量不再需要使用时,可以使用delete操作符释放它所占用的内存,如下所示:
        delete ptr;  // 释放ptr所指向的内存
    
  • 下面的实例使用了上面的概念,演示了如何使用new和delete的运算符
        #include "iostream"using namespace std;int main(){double *ptr = NULL;   // 初始化为null的指针ptr = new double;   // 为变量请求内存*ptr = 3.14;   // 在分配的地址存储值cout << "*ptr = " << *ptr << endl;delete ptr;   // 释放内存return 0;}
    

3.数组的动态内存分配

  • 假设要为一个字符数组(一个有20个字符的字符串)分配内存,可以使用上面实例中的语法来为数组动态地分配内存,如下所示:

        char *ptr = NULL;   // 初始化为 null 的指针ptr = new char[20];  // 为变量请求内存
    
  • 删除刚创建的数组,语句如下:
        delete [] ptr;     // 删除 pvalue 所指向的数组
    
  • 下面是new操作符的通用语法,可以为多维数组分配内存,如下所示:
        // 一维数组如下int *array = new int [m];   // 动态分配,数组长度为 mdelete [] array;  //释放内存-------------------------------------------------------------------------------// 二维数组如下int **array;// 假定数组第一维长度为m, 第二维长度为n// 动态分配空间array = new int *[m];for(int i = 0; i < m; i++)array[i] = new int [n];// 释放for(int i = 0; i < m; i++)delete [] array[i];delete [] array;
    
  • 二维数组实例测试
        // 二维数组int **p;int i, j;  // p[4][8]// 开始分配4行8列的二维数组数据p = new int *[4];for(i = 0; i < 4; i++)p[i] = new int [8];for(i = 0; i < 4; i++){for(j = 0; j < 8; j++)p[i][j] = j * i;}// 打印数据for(i = 0; i < 4; i++){for(j = 0; j < 8; j++){if(j == 0)cout << endl;cout << p[i][j] << "\t";}}cout << endl;// 开始释放申请的堆for(i = 0; i < 4; i++)delete [] p[i];delete p;cout << "-------------------------------\n";
    
  • 三维数组测试实例
        // 三维数组int i1, j1, k1; //p[2][3][4]int ***pt;pt = new int **[2];for(i1 =0; i1 < 2; i1++){pt[i1] = new int *[3];for(j1 = 0;j1<3;j1++)pt[i1][j1] = new int[4];} // 输出pt[i][j][k]三维数据for(i1 = 0;i1 <2;i1++){for(j1=0;j1 <3;j1++){for(k1=0; k1 < 4; k1++){pt[i1][j1][k1] = i1 + j1 + k1;cout << pt[i1][j1][k1] << " ";}cout << endl;}cout << endl;}// 释放内存for(i1 = 0; i1 < 2; i1++){for(j1 = 0; j1 < 3; j1++)delete [] pt[i1][j1];}for(i1 = 0; i1 < 2; i1++)delete [] pt[i1];delete [] pt;cout << "-------------------------------\n";
    

4.对象的动态内存分配

  • 对象与简单的数据类型没有什么不同,例如,请看下面的代码,将使用一个对象数组来理清这一概念,如果要为一个包含4个Box对象的数组分配内存,构造函数将被调用4次.同样地,当删除这些对象时,析构函数也将被调用相同的次数(4次)。

        // 对象的动态内存分配class Box{public:Box(){cout << "调用构造函数\n";}~Box(){cout << "调用析构函数\n";}};Box *boxarray = new Box[4];delete [] boxarray;  // 删除数组
    

5.动态内存分配中的细节知识点

  • delete与delete []区别

    • 针对简单类型,使用new分配后的不管是数组还是非数组形式内存空间用两种方式均可,此种情况中的释放效果相同。原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理。在析构时,系统并不会调用析构函数,它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间(在分配过程中 系统会记录分配内存的大小等信息,此信息保存在结构体_CrtMemBlockHeader中,具体情况可参看VC安装目录下CRT\SRC\DBGDEL.cpp)。如:

          int *a = new int a[10];delete a;delete [] a;
      
    • 针对类class,两种方式体现出具体差异
      • delete a: 仅释放了a指针指向的全部内存空间,但是只调用了a[0]对象的析构函数,剩下的从a[1]到a[9]这9个用户自行分配的m_buffer对应内存空间将不能释放,从而造成内存泄漏。
      • delete [] a: 调用使用类对象的析构函数释放用户自己分配内存空间并且释放了a指针指向的全部内存空间。
          class A{private:char *m_buffer;int m_len;public:A(){m_buffer = new char[m_len];}      ~A(){delete [] m_buffer;}};A *a = new A[10];delete a;delete [] a;
      
    • 总结:如果ptr代表一个用new申请的内存返回的内存空间地址,即所谓的指针,则:
      • delete ptr: 代表用来释放内存,且只用来释放ptr指向的内存
      • delete [] ptr: 用来释放ptr指向的内存,还逐一调用数组中每个对象的destructor!!
      • 对于像int/char/long/int*/struct等简单数据类型,由于对象没有destructor,所以用delete和delete []是一样的!但是如果是C++对象数组就不同了
  • new和malloc内部的实现方式上的区别
    • new的功能是在堆区新建一个对象,并返回该对象的指针。所谓的新建对象的意思就是,将调用该类的构造函数,因为如果不构造的话,就不能称之为一个对象;而malloc只是机械的分配一块内存,如果用malloc在堆区创建一个对象的话,是不会调用构造函数的。严格来说,用malloc不能算是新建了一个对象,只能说是分配了一块与该类对象匹配的内存而已,然后强行把它解释为这是一个对象,按这个逻辑来,也不存在构造函数什么事。
    • 用delete去释放一个堆区的对象,会调用该对象的析构函数;用free去释放一个堆区的对象,不会调用该对象的析构函数
          // new和malloc的区别class TEST{private:int num1;int num2;public:TEST(){num1 = 10;num2 = 20;}void Print(){cout << num1 << " " << num2 << endl;}};/*用malloc()函数在堆区分配一块内存空间,然后对该块内存空间进行强制类型(TEST*)转换解释为是一个TEST类对象,这不会调用TEST的默认构造函数*/TEST *t_obj1 = (TEST *)malloc(sizeof(TEST));t_obj1->Print();// 用new在堆区创建一个TEST类的对象,这会调用TEST类的默认构造函数TEST *t_obj2 = new TEST;t_obj2->Print();
      

C++中的动态内存分配相关推荐

  1. C语言中的动态内存分配

    大家好,今天简单讲一讲C语言中的动态内存分配. 补充:C程序中的内存块. 在C程序中,通常将内存划分为以下六个区域: (1)内核区域.这块区域是操作系统的,用户不能使用. (2)栈区.主要用于存放运行 ...

  2. C中的malloc:C中的动态内存分配

    什么是C中的malloc()? (What is malloc() in C?) malloc() is a library function that allows C to allocate me ...

  3. C++和C语言中的动态内存分配的区别

    在C语言和C++中都会用到动态内存的申请分配的问题,两者之间申请动态内存分配还是区别的. 在C++中的动态内存的分配 1.C++通过new关键字进行动态内存的分配.new关键字是C++内置的一个关键字 ...

  4. SylixOS中的动态内存分配【14】--- cache API中的非缓存内存分配接口实现原理

    实现原理 cache API中的非缓存内存分配接口是通过内核堆或arch API接口实现的. 如果CPU没有cache则cache API应该通过宏配置去掉,即使没有去掉实际也会变成内核堆接口的调用. ...

  5. linux 在指定区域分配内存 c语言,C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存...

    一.malloc/free概述 malloc是在C语言中用于在程序运行时在堆中进行动态内存分配的库函数.free是进行内存释放的库函数. 1.函数原型 #include void *malloc( s ...

  6. C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存

    最新个人博客 shankusu.me 以下内容转载或参考或引用自 https://blog.csdn.net/zxx910509/article/details/62881131 一.malloc/f ...

  7. 【C++】动态内存分配详解(new/new[]和delete/delete[])

    原文链接:https://blog.csdn.net/qq_40416052/article/details/82493916 代码还是原文看着方便,在此不调整格式了 一.为什么需要动态内存分配? 在 ...

  8. C语言数组用到的动态内存分配

    动态内存分配 在学习数组的过程中,在输入数组时,原本想过scanf定义数组的大小再输入数组的各值,却报错. 发现原因: 1.定义数组的时必须指定数组长度 2.数组长度是在编译期就必须决定的 所以此时需 ...

  9. 【C语言进阶深度学习记录】三十三 C语言中动态内存分配

    如何在程序运行的时候动态给程序分配内存? 文章目录 1 动态内存分配的意义 1.1 C语言中如何动态申请内存空间 1.2 malloc和free的用法 1.3 calloc与realloc 1.31 ...

最新文章

  1. 对python的认识800字_我对python里True和False的理解
  2. UIView加任意边框(Masonry)
  3. mysql主从skip1677_解决字符集不同引起的主从同步异常1677报错问题
  4. 用户界面框架jQuery EasyUI示例大全之DataGrid(1/4)
  5. 怎么使用socket在云服务上通信步骤(可支持TCP或UDP)
  6. 这些AI大咖的实践干货,从事人工智能的你应该知道
  7. Microsoft Edge 83 稳定版发布
  8. 【TensorFlow】TensorFlow快速入门
  9. 初学体验是兴趣养成的重要土壤
  10. java redis事务_Redis事务
  11. OC中方法与函数的区别
  12. 项目实施之预防注入漏洞
  13. python应用体系_Python金融应用之基金业绩评价体系构建
  14. 为什么Excel表格只有部分单元格可编辑?
  15. 春季学习报告 4.19
  16. html5 扫描条码,原 HTML5+规范:barcode(条码扫描)
  17. 浅谈我国中小企业融资的问题及对策_毕业论文(20180404104959)
  18. 微信小程序之实现到商品列表跳转商品详情页
  19. pg数据库数据量很小但是data目录很大的排查思路
  20. Linux系统中用命令行清空垃圾箱Trash

热门文章

  1. 自学大数据需要从哪里入手 收藏了一份详细的学习路线图
  2. 手机屏幕的物理分辨率和逻辑分辨率
  3. phpstorm 快捷键
  4. (转) eclipse项目中.classpath文件详解
  5. Eclipse和intellij idea 快捷键对比
  6. jquery.min.map 404 (Not Found)出错的原因及解决办法
  7. VMware的网卡设置模式
  8. ntoskrnl损坏
  9. RHEL系统启动流程
  10. Mycat实现读写分离