c++中new与delete,new[]与delete[]

你不知道的c++之new与delete和new []与delete[]

有如下代码

 

 

反汇编如下

 

查看代码发现并没有什么不同

因为int 类型在c++中 不是对象,在构造时不需要调用构造函数,销毁时不用调用析构函数,所以直接分配,回收空间就行了

修改代码如下

 

反汇编如下

 

 

 

看到区别了?

发现编译器在遇到非内置对象使用new和new[]与内置对象使用new与new[]做了不同处理

而且在对非内置对象使用new与new[]时也做了不同的处理

new[]并没有“call @ILT+65(father::father)”而是“call  `eh vector constructor iterator'” ,那么在“call  `eh vector constructor iterator'“时发生了什么?

首先我们根据反汇编代码来画出此调用时main函数的栈空间

 

然后查看此调用的反汇编代码

 

首先我们从画红线的操作开始分析

mov  ecx,dword ptr [ebp+8] 把dword ptr [ebp+8]单元的值放入ecx寄存器

call  dword ptr [ebp+14h]  调用dword ptr [ebp+14h]单元存放的函数

我们查看栈帧可看到dword ptr [ebp+8]存放的是q+4,  dword ptr [ebp+14h]存放的是构造函数father()的地址

现在你知道这两个操作的做用是什么了?

第一个操作为构造函数传入this指针(q+4)做参数,第二个操作调用构造函数

至于为什么会传入q+4而不是q做参数等会再分析

下面让我们来看接下来的3个操作

mov  edx,dword ptr [ebp+8]

add   edx,dword ptr [ebp+0Ch]

mov  dword ptr [ebp+8],edx

这三个操作就是把dword ptr [ebp+8]单元的值与dword ptr [ebp+0Ch]单元的值相加再存入dword ptr [ebp+8]单元(this+4做为下次调用构造函数的this参数)

查看栈帧会看到dword ptr [ebp+0Ch]单元存放的是4,4代表什么?

4代表刚刚被构造对象的大小,

接着的操作执行了jmp操作,查看跳转地址发现跳到了

0040EEFA   mov  eax,dword ptr [ebp-1Ch]此处

来看下接下来的5个操作和此操作是在做什么?

mov         eax,dword ptr [ebp-1Ch]

add         eax,1

mov         dword ptr [ebp-1Ch],eax

mov         ecx,dword ptr [ebp-1Ch]

cmp         ecx,dword ptr [ebp+10h]

jge         `eh vector constructor iterator'+5Ch (0040ef1c)

这6个操作就是把dword ptr [ebp-1Ch]单元的值加一再放回去,然后与dword ptr [ebp+10h]单元的值比较如果大于等于此单元的值代表已经完成了对象构造

查看栈帧发现dword ptr [ebp+10h]单元的值是3,3代表什么?数组的大小

查看代码发现dword ptr [ebp-1Ch]单元的值是0,

所以此6个操作的作用就是保证所有数组元素都能完成构造

下面让我们来分析构造第一个对象时为什么会为构造函数传入q+4做this指针,要解决这个问题我们要回到使用new[]操作符时

 

 

查看反汇编代码会发现

编译器为第二个operator new()传入的参数是16而不是12,多出的4个字节是干什么的?

 

继续查看红线标识的操作你会发现数组的大小3被放到了operator new()所分配的空间的前四个字节中,现在你知道为什么在构造第一个对象时会传入q+4做this指针了?

因为q指向的是3,q+4指向的才是为第一个对象分配的空间

然而但是你会发现好像在对象空间存放个3,并没有什么鸟用,到现在为止根本没用到这个位置的3,一直用的都是位于栈中的3。

下面该delete[]上场了

当你调用delete[]时那栈中的3还会存在???

 

然而查看代码又让你失望了,你发现在delete p时编译器生成了一条push 1指令,在delete[] q时编译器生成了一条push 3指令,既然在这编译器已经给出了要析构对象的个数,那对象空间中前四个字节存放的那个3又有何用?

下面来查看father::`vector deleting destructor'的反汇编代码

 

分析红线标识的操作,dword ptr[ebp+8]就是刚刚被压栈的3,把3和2 比较这有什么用?

为什么是3与2比较而不是和其它的数字比较?

如果数组的大小为2 ,那么将会执行不一样的操作,这有点说不过去呀,为什么会对2做特殊对待???

还有为什么delete p时会push 1做参数??

继续查看father::`scalar deleting destructor'

 

你会发现编译器会让1与1比较,这是为什么?

1,2,3你不觉得有点奇怪?我觉得有点,于是我修改代码如下

 

查看反汇编代码

 

会发现编译器还是会生成push 3,而不是你认为的push 5,原来这只是个巧合。

哈哈现在那对象空间中的前四个字节有用了?

现在我们来看下那四个字节到底有没有被使用到,继续查看father::`vector deleting destructor'的反汇编代码

 

Mov edx, dword ptr[ecx-4]就是把那四个字节放入edx寄存器中,你可能会问ecx中的值不是this(第一个对象)?那这里的ecx-4(this-4)是什么意思?

下面让我们查看一下father *q=new father[3

]的代码

 

 

红线标识的操作就是把operator new()返回的指针向前移动4个字节指向对象1,这就是为什么会使用this-4做地址去取得3

通过上面的分析可以看到在c++中new与delete,new[]与delete[]要配对使用

 

注:vc++6.0

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值