在堆中创建对象
我们可以在什么地方创建对象?
- 全局变量区,在函数外面
- 在栈中创建对象,也就是函数内
- 在堆中创建对象
注意:之前一直提到的堆栈实际上是两个概念->堆、栈,我们之前所讲的就是栈,从本章开始要严格区分。
在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 = newint[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吧。
标签:00,C++,Person,FF,dword,new,delete From: https://blog.51cto.com/u_11908275/6941584