说明:本文有理解和解释错误之处还请见谅
自己从接触new这个关键字,看了一些别人使用new的代码,知道new是自己在堆中申请的空间,但是一直不明白是怎么生成的。下面结合汇编来说一下new这个关键字。
一、用new申请存放基本类型的空间
1、申请一个整型数据,初始值为3
int* pa = new int(3); //在堆中申请一个整型数据3,相当于int a = 3
/*观察汇编:
push 4 //编译器自己知道一个int的大小为4个字节
call operator new (0D51320h) //调用new,在堆中申请了4个字节的空间,将在堆中申请的的地址传递个EAX,此时0137FFB8
add esp,4
mov dword ptr [ebp-110h],eax //将EAX的值存放到栈中(此时0137FFB8存放在栈中)
cmp dword ptr [ebp-110h],0
je Test+70h (0D524E0h)
mov eax,dword ptr [ebp-110h]
mov dword ptr [eax],3 //将要初始化的整型数值3存入地址为0x0137FFB8中(此时3在堆中)
mov ecx,dword ptr [ebp-110h]
mov dword ptr [ebp-16Ch],ecx
jmp Test+7Ah (0D524EAh)
mov dword ptr [ebp-16Ch],0
mov edx,dword ptr [ebp-16Ch] //EDX = 0137FFB8
mov dword ptr [pa],edx //将地址0x0137FFB8给pa,那么papa = 0x0137FFB8 03 00 00 00
*/
new申请的空间是在堆中,但是我们定义的指针类型的pa是在栈中,之前一直不理解new之后的东西为什么必须是一个指针类型的变量接收,现在理解了,因为new之后返回的就是一个地址,一个地址啊,所以就用一个指针类型的变量来接收。。。
2、申请一个没有初始化的存放int类型的数组
int* pb = new int[3];
/*
00D524F3 push 0Ch //编译器知道3个int的大小为12个字节
00D524F5 call operator new[] (0D513ACh)
00D524FA add esp,4
00D524FD mov dword ptr [ebp-11Ch],eax
00D52503 mov eax,dword ptr [ebp-11Ch]
00D52509 mov dword ptr [pb],eax //将在堆中申请的地址给指针pb,此时pb指针指向堆中的空间由cd填充,因为没有初始化
*/
3、申请一个默认用0初始化的存放int类型的数组(大小12个字节)
int* pd = new int[3]();//在堆中申请一个数组,数组大小为3个int,即3X4=12个字节,初始化为0,相当于int arr[3] = {};
/*
00D5251C push 0Ch
00D5251D call operator new[] (0D513ACh) //调用new,将申请的地址返回给eax
00D52522 add esp,4
00D52525 mov dword ptr [ebp-134h],eax
00D5252B cmp dword ptr [ebp-134h],0
00D52532 je Test+0EAh (0D5255Ah)
00D52534 mov ecx,dword ptr [ebp-128h]
00D5253A push ecx
00D5253B push 0
00D5253D mov edx,dword ptr [ebp-134h]
00D52543 push edx
00D52544 call _memset (0D5110Eh) //调用memset函数,数组里面是值默认用0初始化
00D52549 add esp,0Ch
00D5254C mov eax,dword ptr [ebp-134h]
00D52552 mov dword ptr [ebp-16Ch],eax
00D52558 jmp Test+0F4h (0D52564h)
00D5255A mov dword ptr [ebp-16Ch],0
00D52564 mov ecx,dword ptr [ebp-16Ch]
00D5256A mov dword ptr [pd],ecx //将在堆中申请的地址给指针pc,此时pc指针指向堆中的空间由0填充
*/
二、用new申请存放类(或结构体)类型的空间
class A
{
int i;
public:
//A() {};
A(int _i) :i(_i*_i) {}
void Say() { printf("i=%d/n", i); }
};
A* Cpa = new A(3);
/*
00D52654 push 4
00D52656 call operator new (0D51320h) //调用new,地址放到eax,此时eax=01378120
00D5265B add esp,4
00D5265E mov dword ptr [ebp-164h],eax
00D52664 mov dword ptr [ebp-4],0
00D5266B cmp dword ptr [ebp-164h],0
00D52672 je Test+219h (0D52689h)
00D52674 push 3
00D52676 mov ecx,dword ptr [ebp-164h]
00D5267C call A::A (0D51096h) //调用类的构造函数,将实参3传入构造函数,运算之后的值存入到eax指向的地址中(堆中存放的值我为9)
00D52681 mov dword ptr [ebp-16Ch],eax
00D52687 jmp Test+223h (0D52693h)
A* Cpa = new A(3);
00D52689 mov dword ptr [ebp-16Ch],0
00D52693 mov eax,dword ptr [ebp-16Ch]
00D52699 mov dword ptr [ebp-158h],eax
00D5269F mov dword ptr [ebp-4],0FFFFFFFFh
00D526A6 mov ecx,dword ptr [ebp-158h]
00D526AC mov dword ptr [Cpa],ecx
*/
对于A* Cpa = new A(3);这句话相当于下面三句话(参考:http://blog.csdn.net/songthin/article/details/1703966)
A* pa = (A*)malloc(sizeof(A));
pa->A::A(3);
return pa;