首页 / 资讯中心 / 文章详情

手把手教你C++——内存管理

手把手教你C++——内存管理 ★ FEATURED ARTICLE
文章目录1.C/C内存管理1.1 内存分布2.C语言中动态内存管理方式malloc/realloc/calloc3.C中内存管理方式3.1 new delete操作内置类型3.2 new和delete操作自定义类型4.operator new和operator delete函数4.1 operator new和operator delete函数5.new和delete的实现原理5.1 内置类型5.2 自定义类型5.3 new/delete和malloc/free的搭配6. 定位new表达式(replacement-new)malloc/free和new/delete的区别1.C/C内存管理1.1 内存分布我们先来看一段代码和相关问题我们先通过这段代码来找找各个所提到的这些变量/指针究竟都存在于哪里globalVar是全局变量所以存在于静态区也就是数据段 CstaticGlobalVar用static修饰的变量存在于静态区也就是数据段 CstaticVar局部变量用static修饰存在于静态区也就是数据段 ClocalVar局部变量存在于栈上 Anum1数组名代表整个数组存在于栈上 Achar2数组名代表整个数组存在于栈上 A*char2char2这个数组名存放的其实是首元素地址那*char2就代表的是‘a’这个字符由于char2这个数组都是存在于函数体内部的局部变量所以就存在于栈上那么作为首元素*char2当然也是在栈上 A*pChar3pChar3前面是char*代表它是个指针指针也是存在于栈上 A**pChar3pChar3这个指针里面存放的是‘a’这个字符的地址所以*pChar3就代表的是‘a’这个字符整个字符串在常量区那‘a’肯定也是在常量区 Dptr1是个指针并且在函数体内存在于栈上 A*ptr1代表新开辟的空间在堆上 B2.C语言中动态内存管理方式malloc/realloc/calloc三者区别malloc申请新的空间时用到realloc在空间不足时用来扩容的calloc申请空间并且将申请出的值初始化为03.C中内存管理方式3.1 new delete操作内置类型voidTest(){//动态申请一个int类型的空间int*ptr4newint;//动态申请一个int类型的空间并且初始化为10int*ptr5newint(10);//动态申请十个int类型的空间int*ptr6newint[10];deleteptr4;deleteptr5;delete[]ptr6;}注意申请和释放单个元素的空间用new和delete申请和释放多个空间要用[ ]new和[ ]delete。注意搭配起来使用3.2 new和delete操作自定义类型#includeiostreamusingnamespacestd;classA{public:A(inta0):_a(a){coutA()endl;}~A(){cout~A()endl;}private:int_a;};intmain(){// new/delete和malloc/free最大的区别就是new/detele不止可以申请新的空间// 而且会自动调用构造和析构函数A*p1(A*)malloc(sizeof(A));A*p2newA(1);free(p1);//new/detele和malloc/free的搭配是固定的不能随意更换delete(p2);}如果类类型想要申请多个空间并且初始化也是可以的我们可以用匿名对象或者是隐式类型转换来初始化4.operator new和operator delete函数4.1 operator new和operator delete函数new和delete都是动态内存申请和释放的操作符。operator new和operator delete函数时系统提供的全局函数new在底层通过调用operator new函数来申请空间delete则在底层通过调用operator delete函数来释放空间operator delete最终还是要通过free来释放空间的5.new和delete的实现原理5.1 内置类型在内置类型中new/delete和malloc/free的功能是基本相似的。不同的就是new/delete申请和释放的是单个空间而new[ ]和delete[ ]申请和释放的是多个空间。而且new在申请空间失败时会抛异常malloc会返回NULL5.2 自定义类型new 的原理:1.调用operator new申请空间2.在申请的空间执行构造函数完成对象构造delete的原理1.在空间上执行析构函数完成对象内部资源清理工作2.调用operator delete函数释放对象空间new[N]原理:1.调用operator new[ ]函数实际上是通过operator new[ ]来调用operator new来完成对N个空间的申请2.在申请的空间上完成N次构造函数delete[ ]原理:1.在要释放的空间上完成析构函数的执行完成N个对象中资源的清理2.调用operator delete[ ]释放空间实际通过operator delete[ ]来调用operator delete来完成对N个空间的释放5.3 new/delete和malloc/free的搭配new/delete和malloc/free的搭配是固定的但是这其中也牵扯一些更加底层的东西为什么对于内置类型搭配错误的时候就没有报错而对于自定义类型搭配错误就会报错呢那我们可以转换到反汇编来看一下我们可以看到对于内置类型来说我申请了10个空间那就是40个字节是没有任何问题的但是对于自定义类型我的每一个类占用的是4个字节但是现在我申请10个类的空间却占用了48个字节为什么多出了8个字节呢这八个字节其实就是在释放这十个空间时是需要调用析构函数的但是编译器并不知道应该调用几次析构函数所以这八个空间里面存放的就是编译器要调用析构函数的次数所以不能直接用free来释放。至于为什么不能用free我们也可以通过观察内存窗口来分析我们来看这两张截图对于内置类型来说内存的地址就是从第一个申请的空间开始的而对于自定义类型我们可以看到图中标记的在申请第一个空间之前还有一小部分空间而这个空间中存放的就是需要调用析构函数的次数。这个地址也就成了这些新申请空间的首地址而调用free也是需要这块空间的首地址的对于我们来说首地址就是0x000002BB1B20BA78但是对于编译器来说首地址是0x000002BB1B20BA70那这样释放空间时就会出现问题6. 定位new表达式(replacement-new)定位new表达式实在以及申请的空间中调用构造函数完成初始化一个对象使用格式new(place address)type或者是new(place address)type(initializer-list)place address必须是一个指针initializer-list必须是类型的初始化列表这两部分加起来就相当于是new对于delete来说也是一样那既然已经有了new和delete为什么还要多此一举用这replacement-new呢其实replacement-new的使用场景并不在这里定位new一般是配合内存池来使用因为从内存池中申请出的内存没有被初始化所以如果是自定义类型的对象需要使用new的定义表达式进行显示构造函数初始化malloc/free和new/delete的区别malloc/free和new/delete共同的地方是他们都是在堆上申请空间并且都需要手动释放malloc/free和new/delete不同的地方是1、malloc和free是函数new和delete是操作符2、malloc申请的空间不会初始化new申请的空间可以初始化3、malloc申请空间时需要手动计算空间的大小并传递而new只需要在后面跟上类型即可如果是多个对象则在[ ]中指定对象个数即可4、malloc返回值为void所以必须要强转但是new不需要强转因为后面跟的是类型*5、malloc申请空间失败时返回值是NULL所以使用时要判断是否为空new是不需要的但是new需要捕获异常申请自定义类型的对象时malloc和free只能申请空间不能调用构造函数和析构函数但是new和delete是可以调用构造函数完成初始化并且调用析构函数释放空间的.
阅读完成 · 觉得有帮助?
咨询建站