C++逆向分析——new和delete new[]和delete[]
在堆中创建对象
我们可以在什么地方创建对象?
-
全局变量区,在函数外面
-
在栈中创建对象,也就是函数内
-
在堆中创建对象
注意:之前一直提到的堆栈实际上是两个概念->堆、栈,我们之前所讲的就是栈,从本章开始要严格区分。
在C语言中,我们可以通过一个函数去申请一块内存,就是malloc(N);申请的这一块内存就是在堆中的。
在堆中创建对象我们可以使用new、delete这两个关键词来创建和释放:
Person* p =
new
Person();
delete p;
我们可以来实际的看一下new、delete这两个关键词主要做了什么。
首先我们使用new关键词的时候会发现,其除了在堆中创建了对象还会调用构造函数:
再跟进看看使用delete,它会释放空间并调用析构函数:
我们想要了解其本质,还是要去跟一下汇编代码,这里跟一下new关键词的执行流程看看其分别调用的函数(跟进call operator new (004012e0)):
而后调用了构造函数: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:
所以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[]的区别:
-
malloc不会调用构造函数
-
new[]会调用构造函数,创建一次则调用一次,例如new Person[10]则调用10次
同理也可以知道free和delete[]的区别。
delete和delete[]是有区别的,如果使用new[]在堆中创建对象,使用delete去释放则只会释放第一个对象,其他的不会释放。
手动实践下:
#include <stdio.h> class Person { private: int age; int sex; public: Person(int a, int b) { age = a; sex = b; } Person() { age = 0; sex = -1; } }; void main() { Person* p = new Person; delete p; // Person* p = new Person[3]; // delete[] p; p = nullptr; return; }
反汇编的代码贴下:
Person* p = new Person; 00275914 6A 08 push 8 ;size==8,因为person空间大小 00275916 E8 FD B7 FF FF call operator new (0271118h) ;malloc好 0027591B 83 C4 04 add esp,4 0027591E 89 85 14 FF FF FF mov dword ptr [ebp-0ECh],eax 00275924 C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0 0027592B 83 BD 14 FF FF FF 00 cmp dword ptr [ebp-0ECh],0 00275932 74 13 je __$EncStackInitStart+5Dh (0275947h) 00275934 8B 8D 14 FF FF FF mov ecx,dword ptr [ebp-0ECh] 0027593A E8 CC BA FF FF call Person::Person (027140Bh) ;在malloc地址基础上去调用构造函数 0027593F 89 85 00 FF FF FF mov dword ptr [ebp-100h],eax 00275945 EB 0A jmp __$EncStackInitStart+67h (0275951h) 00275947 C7 85 00 FF FF FF 00 00 00 00 mov dword ptr [ebp-100h],0 00275951 8B 85 00 FF FF FF mov eax,dword ptr [ebp-100h] 00275957 89 85 20 FF FF FF mov dword ptr [ebp-0E0h],eax 0027595D C7 45 FC FF FF FF FF mov dword ptr [ebp-4],0FFFFFFFFh 00275964 8B 8D 20 FF FF FF mov ecx,dword ptr [ebp-0E0h] 0027596A 89 4D EC mov dword ptr [p],ecx delete p; 0027596D 8B 45 EC mov eax,dword ptr [p] 00275970 89 85 08 FF FF FF mov dword ptr [ebp-0F8h],eax 00275976 6A 08 push 8 00275978 8B 8D 08 FF FF FF mov ecx,dword ptr [ebp-0F8h] 0027597E 51 push ecx 0027597F E8 FE B6 FF FF call operator delete (0271082h) ;delete 00275984 83 C4 08 add esp,8 00275987 83 BD 08 FF FF FF 00 cmp dword ptr [ebp-0F8h],0 0027598E 75 0C jne __$EncStackInitStart+0B2h (027599Ch) 00275990 C7 85 00 FF FF FF 00 00 00 00 mov dword ptr [ebp-100h],0 0027599A EB 10 jmp __$EncStackInitStart+0C2h (02759ACh) 0027599C C7 45 EC 23 81 00 00 mov dword ptr [p],8123h 002759A3 8B 55 EC mov edx,dword ptr [p] 002759A6 89 95 00 FF FF FF mov dword ptr [ebp-100h],edx // Person* p = new Person[3]; // delete[] p; p = nullptr; 002759AC C7 45 EC 00 00 00 00 mov dword ptr [p],0
return;
类似的讲解:
换成数组:
#include <stdio.h> class Person { private: int age; int sex; public: Person(int a, int b) { age = a; sex = b; } Person() { age = 0; sex = -1; } }; void main() { Person* p = new Person[3]; delete[] p; p = nullptr; return; }
反汇编比较复杂,todo吧。