C++逆向分析——new和delete new[]和delete[]

发布时间 2023-04-09 10:54:30作者: bonelee

在堆中创建对象

我们可以在什么地方创建对象?

  1. 全局变量区,在函数外面

  2. 在栈中创建对象,也就是函数内

  3. 在堆中创建对象

注意:之前一直提到的堆栈实际上是两个概念->堆、栈,我们之前所讲的就是栈,从本章开始要严格区分。

在C语言中,我们可以通过一个函数去申请一块内存,就是malloc(N);申请的这一块内存就是在堆中的。

在堆中创建对象我们可以使用new、delete这两个关键词来创建和释放:

Person* p = new Person();
delete p;

我们可以来实际的看一下new、delete这两个关键词主要做了什么。

首先我们使用new关键词的时候会发现,其除了在堆中创建了对象还会调用构造函数:

images/download/attachments/12714553/image2021-4-4_22-10-14.png

再跟进看看使用delete,它会释放空间并调用析构函数:

images/download/attachments/12714553/image2021-4-4_22-11-41.png

我们想要了解其本质,还是要去跟一下汇编代码,这里跟一下new关键词的执行流程看看其分别调用的函数(跟进call operator new (004012e0)):

images/download/attachments/12714553/image2021-4-4_22-17-13.png

而后调用了构造函数:call @ILT+0(Person::Person) (00401005)

我们再来跟下malloc函数的调用步骤:

call malloc (00401a20) → _nh_malloc_dbg → _heap_alloc_dbg → _heap_alloc_base → HeapAlloc

那么这时候一下就清楚了new的本质,实际上就是malloc+构造函数,同样的方法可以跟下delete看下它跟free函数。

跟进delete关键词,会发现其会先调用析构函数函数然后再去调用operator delete然后就是_free_dbg:

images/download/attachments/12714553/image2021-4-4_22-30-48.png

所以delete的本质就是析构函数+free。

如果我们想要在堆中申请数组,需要使用new[]、delete[]这两个关键词来创建和释放。

// C、C++的方式在堆中申请、释放int数组
int* p = (int*)malloc(sizeof(int)*10); free(p);
int* p = new int[10]; delete[] p;
 
// C、C++的方式在堆中申请、释放Class类型数组
Person* p = (Person*)malloc(sizeof(Person)*10); free(p);
Person* p = new Person[10]; delete[] p;

malloc和new[]的区别:

  1. malloc不会调用构造函数

  2. new[]会调用构造函数,创建一次则调用一次,例如new Person[10]则调用10次

同理也可以知道free和delete[]的区别。

delete和delete[]是有区别的,如果使用new[]在堆中创建对象,使用delete去释放则只会释放第一个对象,其他的不会释放。