C++中的动态内存分配
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分配后的不管是数组还是非数组形式内存空间用两种方式均可,此种情况中的释放效果相同。原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理。在析构时,系统并不会调用析构函数,它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间(在分配过程中 系统会记录分配内存的大小等信息,此信息保存在结构体_CrtMemBlockHeader中,具体情况可参看VC安装目录下CRT\SRC\DBGDEL.cpp)。如:
- 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++中的动态内存分配相关推荐
- C语言中的动态内存分配
大家好,今天简单讲一讲C语言中的动态内存分配. 补充:C程序中的内存块. 在C程序中,通常将内存划分为以下六个区域: (1)内核区域.这块区域是操作系统的,用户不能使用. (2)栈区.主要用于存放运行 ...
- C中的malloc:C中的动态内存分配
什么是C中的malloc()? (What is malloc() in C?) malloc() is a library function that allows C to allocate me ...
- C++和C语言中的动态内存分配的区别
在C语言和C++中都会用到动态内存的申请分配的问题,两者之间申请动态内存分配还是区别的. 在C++中的动态内存的分配 1.C++通过new关键字进行动态内存的分配.new关键字是C++内置的一个关键字 ...
- SylixOS中的动态内存分配【14】--- cache API中的非缓存内存分配接口实现原理
实现原理 cache API中的非缓存内存分配接口是通过内核堆或arch API接口实现的. 如果CPU没有cache则cache API应该通过宏配置去掉,即使没有去掉实际也会变成内核堆接口的调用. ...
- linux 在指定区域分配内存 c语言,C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存...
一.malloc/free概述 malloc是在C语言中用于在程序运行时在堆中进行动态内存分配的库函数.free是进行内存释放的库函数. 1.函数原型 #include void *malloc( s ...
- C语言动态内存分配:(一)malloc/free的实现及malloc实际分配/释放的内存
最新个人博客 shankusu.me 以下内容转载或参考或引用自 https://blog.csdn.net/zxx910509/article/details/62881131 一.malloc/f ...
- 【C++】动态内存分配详解(new/new[]和delete/delete[])
原文链接:https://blog.csdn.net/qq_40416052/article/details/82493916 代码还是原文看着方便,在此不调整格式了 一.为什么需要动态内存分配? 在 ...
- C语言数组用到的动态内存分配
动态内存分配 在学习数组的过程中,在输入数组时,原本想过scanf定义数组的大小再输入数组的各值,却报错. 发现原因: 1.定义数组的时必须指定数组长度 2.数组长度是在编译期就必须决定的 所以此时需 ...
- 【C语言进阶深度学习记录】三十三 C语言中动态内存分配
如何在程序运行的时候动态给程序分配内存? 文章目录 1 动态内存分配的意义 1.1 C语言中如何动态申请内存空间 1.2 malloc和free的用法 1.3 calloc与realloc 1.31 ...
最新文章
- 对python的认识800字_我对python里True和False的理解
- UIView加任意边框(Masonry)
- mysql主从skip1677_解决字符集不同引起的主从同步异常1677报错问题
- 用户界面框架jQuery EasyUI示例大全之DataGrid(1/4)
- 怎么使用socket在云服务上通信步骤(可支持TCP或UDP)
- 这些AI大咖的实践干货,从事人工智能的你应该知道
- Microsoft Edge 83 稳定版发布
- 【TensorFlow】TensorFlow快速入门
- 初学体验是兴趣养成的重要土壤
- java redis事务_Redis事务
- OC中方法与函数的区别
- 项目实施之预防注入漏洞
- python应用体系_Python金融应用之基金业绩评价体系构建
- 为什么Excel表格只有部分单元格可编辑?
- 春季学习报告 4.19
- html5 扫描条码,原 HTML5+规范:barcode(条码扫描)
- 浅谈我国中小企业融资的问题及对策_毕业论文(20180404104959)
- 微信小程序之实现到商品列表跳转商品详情页
- pg数据库数据量很小但是data目录很大的排查思路
- Linux系统中用命令行清空垃圾箱Trash