牛骨文教育服务平台(让学习变的简单)
博文笔记

new和delete时究竟发生了什么?

创建时间:2007-05-28 投稿人: 浏览次数:465

 在C++中,当用户调用new和delete时,实际上分别发生了如下事情:

new:

1. 调用::operator new(相当于malloc), 分配一块内存;

2. 检查第一步内存分配的结果,如果未被正常分配(比如系统资源耗尽时),抛出异常,直接返回,接下来的步骤不会执行;

3. 调用构造函数.

delete:

1. 检查指定要删除的内存,如果已经为空,直接返回,接下来的步骤不会执行;

2. 调用析构函数;

3. 调用::operator delete(相当于free),释放内存.

下面我们通过查看测试代码的相应汇编代码来证实上述观点.

测试代码:

#include "stdafx.h"
#include <iostream>
using namespace std;

class MyClass
...{
public:
   MyClass(const char*) ...{}
   ~MyClass() ...{}
   operator char() ...{return "a";}
protected:
private:
   char* m_data;
};

int _tmain(int argc, _TCHAR* argv[])
...{
    MyClass* my = new MyClass("Hello!");
   delete my;
   
   char memory[sizeof(MyClass)];
   void* p = memory; 
   MyClass* second = new (p) MyClass("World!");
   second->~MyClass();
   
   return 0;
}

相应的汇编代码如下:

int _tmain(int argc, _TCHAR* argv[])
...{
004136E0  push        ebp  
……
   MyClass* my = new MyClass("Hello!");
0041371D  push        4    
0041371F  call        operator new (411190h)    // 步骤1
00413724  add         esp,4 
00413727  mov         dword ptr [ebp-134h],eax 
0041372D  mov         dword ptr [ebp-4],0 
00413734  cmp         dword ptr [ebp-134h],0 
0041373B  je          wmain+75h (413755h)       // 步骤2
0041373D  push        offset string "Hello!" (41676Ch) 
00413742  mov         ecx,dword ptr [ebp-134h] 
00413748  call        MyClass::MyClass (41116Dh)    // 步骤3
0041374D  mov         dword ptr [ebp-148h],eax 
00413753  jmp         wmain+7Fh (41375Fh) 
00413755  mov         dword ptr [ebp-148h],0 
0041375F  mov         eax,dword ptr [ebp-148h] 
00413765  mov         dword ptr [ebp-140h],eax 
0041376B  mov         dword ptr [ebp-4],0FFFFFFFFh 
00413772  mov         ecx,dword ptr [ebp-140h] 
00413778  mov         dword ptr [ebp-14h],ecx 
   delete my;
0041377B  mov         eax,dword ptr [ebp-14h] 
0041377E  mov         dword ptr [ebp-11Ch],eax 
00413784  mov         ecx,dword ptr [ebp-11Ch] 
0041378A  mov         dword ptr [ebp-128h],ecx 
00413790  cmp         dword ptr [ebp-128h],0 
00413797  je          wmain+0CEh (4137AEh)       // 步骤1
00413799  push        1    
0041379B  mov         ecx,dword ptr [ebp-128h] 
004137A1  call        MyClass::`scalar deleting destructor(41100Ah)   // 步骤2和步骤3
004137A6  mov         dword ptr [ebp-148h],eax 
004137AC  jmp         wmain+0D8h (4137B8h) 
004137AE  mov         dword ptr [ebp-148h],0 
   
   char memory[sizeof(MyClass)];
   void* p = memory; 
004137B8  lea         eax,[ebp-20h] 
004137BB  mov         dword ptr [ebp-2Ch],eax 
   MyClass* second = new (p) MyClass("World!");
004137BE  mov         eax,dword ptr [ebp-2Ch] 
004137C1  push        eax  
004137C2  push        4    
004137C4  call        operator new (4111E0h)       // 步骤1
004137C9  add         esp,8 
004137CC  mov         dword ptr [ebp-104h],eax 
004137D2  mov         dword ptr [ebp-4],1 
004137D9  cmp         dword ptr [ebp-104h],0 
004137E0  je          wmain+11Ah (4137FAh)         // 步骤2
004137E2  push        offset string "World!" (4166FCh) 
004137E7  mov         ecx,dword ptr [ebp-104h] 
004137ED  call        MyClass::MyClass (41116Dh)   // 步骤3
004137F2  mov         dword ptr [ebp-148h],eax 
004137F8  jmp         wmain+124h (413804h) 
004137FA  mov         dword ptr [ebp-148h],0 
00413804  mov         ecx,dword ptr [ebp-148h] 
0041380A  mov         dword ptr [ebp-110h],ecx 
00413810  mov         dword ptr [ebp-4],0FFFFFFFFh 
00413817  mov         edx,dword ptr [ebp-110h] 
0041381D  mov         dword ptr [ebp-38h],edx 
   second->~MyClass();
00413820  push        0    
00413822  mov         ecx,dword ptr [ebp-38h] 
00413825  call        MyClass::`scalar deleting destructor" (41100Ah) 
   
   return 0;
0041382A  xor         eax,eax 
}
0041382C  push        edx  
……

这里需要特别注意的是:

1. 定位创建(placement new)的方法, 即new(p) MyClass("Hello"),不管p是否被正确创建,定位创建的过程与一般创建的过程是一样的,即也经历3个主要步骤.

2. 汇编代码中所说的scalar deleting destructor是编译器自动生成的, 相当于先执行析构函数再执行delete操作,相关信息可参考http://www.thescripts.com/forum/thread263644.html

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。