C++内存管理——new和delete深度剖析

一、复习内存管理有关基础知识

在学习C++以前,我们了解到内存管理涉及到地址空间,所谓的地址空间并不是实际存在的,因此地址空间又称虚拟地址空间。

#include<iostream>
using namespace std;

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
    static int staticVal = 1;
    int localVar = 1;
    char a2[] = "abcd";
    char*a3 = "abcd";
    int*p1 = (int*)malloc(sizeof(int)* 4);
    int*p2 = (int*)calloc(4, sizeof(int));
    int*p3 = (int*)realloc(p2, sizeof(int)* 4);
    int*p4 = new int;
    int*p5 = new int(3);
    int*p6 = new int[3];
    free(p1);
    free(p3);
    delete p4;
    delete p5;
    delete[] p6;
}

上面定义的这些变量的存储位置如图所示:
这里写图片描述

函数体内定义的一般变量存储在栈上的,会随栈帧的创建、销毁而创建销毁:具体创建过程与销毁过程可参考:C语言栈帧剖析
https://blog.csdn.net/vickers_xiaowei/article/details/79512762

二、new和delete深度剖析

我们知道C语言的malloc函数和free函数是用来在堆上动态开辟内存的,但是malloc函数仅仅开辟了定义大小的空间,例如:

int*p=(int*)malloc(sizeof(int)*n);
assert(p);
free(p);

这里动态开辟了4n个字节,这里sizeof(int)是在手动计算一个整形的字节数,开辟了n个整形的空间,返回值是 void*,所以需要类型转化为int*。
同理,free函数也只是释放掉了这段内存空间,将其以void*类型归还给系统。

int*p1=new int;
int*p2=new int(3);//给变量初始化为3
int*p3=new int[3];//开辟了容量为3的数组
delete p1;
delete p2;
delete[] p3;

new和delete不是函数,而是操作符。
只需要给定变量类型个数,new会自己算出空间大小,new动态开辟了的空间,还调用了构造函数为变量进行初始化。
delete调用析构函数进行清理工作后,释放空间。
深度剖析:
必须清楚:operator new和operator delete和函数重载没有毛关系,new和delete不是函数,是内置操作符。
(一).new/delete 和operator new/operator delete和malloc/free的关系
这里写图片描述
new:
1、调用operator new函数动态开辟内存,申请内存失败,抛异常。operator new实质是对malloc的封装。
这里写图片描述
2、调用构造函数进行初始化对象。
这里写图片描述
delete:
1、调用析构函数,清理对象空间。
这里写图片描述
2、调用operator delete进行空间释放,operator new实质是对free的封装。
这里写图片描述
(二).new[ ]时底层处理的机制
operator new 的返回值count是申请空间的大小:
这里写图片描述
new type[],type 显示定义析构函数 才会多开4个字节存储对象个数。
这里写图片描述
(三)动态开辟空间一定注意使用方式的匹配问题:

malloc————free
new———————delete
new[]-----delete[]

自定义了析构函数的类型在new[ ]多开的那4个字节,存储在申请空间的低地址,也就是说动态开辟的这段空间存储了对象个数之后才存储对象本体。

这也就是说,如果你在使用自定义类型的new[ ]和delete[ ],如果使用不匹配可能会让编译器去释放的起点位置有错误,导致内存泄漏问题,致使程序挂掉。

猜你喜欢

转载自blog.csdn.net/Vickers_xiaowei/article/details/80686921
今日推荐