今天在测试程序测试的过程中,发现用new运算符申请空间失败,跟踪并分析了一下new的源码
2. operator new[]的代码
void *__CRTDECL operator new(size_t) /*_THROW1(std::bad_alloc)*/; void * operator new[]( size_t cb ) { void *res = operator new(cb); RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0)); return res; }
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) //申请空间 if (_callnewh(size) == 0) //若申请失败则调用处理函数 { // report no memory static const std::bad_alloc nomem; _RAISE(nomem); // #define _RAISE(x) ::std:: _Throw(x) 抛出nomem的异常 } return (p); }
3. 原本我们的理解是,利用new运算符去创建对象,会做如下工作:
但是我们在源码中发现new中只是做了申请内存空间的工作,那作用不是跟MALLOC一样嘛,就多了个异常处理的功能。
现在一段示例代码:
class Test { public: Test() { cout<<"Constructor Test"<<endl; } ~Test() { cout<<"Destructor Test"<<endl; } }; int _tmain(int argc, _TCHAR* argv[]) { Test* p = new Test(); delete p; Test* p1 = new Test[10]; delete []p1; return 0; }
看下红色语句对应的汇编代码:来分析一下这些语句究竟干了什么?
Test* p = new Test(); 004114ED push 1 //1是对象大小,将参数入栈 004114EF call operator new (4111EFh) //调用operator new()函数 004114F4 add esp,4 004114F7 mov dword ptr [ebp-110h],eax //eax中存放的是申请到的空间的内存首地址 004114FD mov dword ptr [ebp-4],0 00411504 cmp dword ptr [ebp-110h],0 //判断指针是否为NULL(ebp-110h) 0041150B je wmain+70h (411520h) 0041150D mov ecx,dword ptr [ebp-110h] //内存空间的地址存放与ecx寄存器中 00411513 call Test::Test (4111C7h) //调用Test类构造函数 00411518 mov dword ptr [ebp-124h],eax 0041151E jmp wmain+7Ah (41152Ah) 00411520 mov dword ptr [ebp-124h],0 0041152A mov eax,dword ptr [ebp-124h] 00411530 mov dword ptr [ebp-11Ch],eax 00411536 mov dword ptr [ebp-4],0FFFFFFFFh 0041153D mov ecx,dword ptr [ebp-11Ch] 00411543 mov dword ptr [ebp-14h],ecx
虽然不是所有的代码都能看懂,但是关键地方的代码加上注释还是能看懂的哈。
delete p的汇编:
delete p;
00411B16 mov eax,dword ptr [ebp-14h]
00411B19 mov dword ptr [ebp-0E0h],eax
00411B1F mov ecx,dword ptr [ebp-0E0h]
00411B25 mov dword ptr [ebp-0ECh],ecx
00411B2B cmp dword ptr [ebp-0ECh],0
00411B32 je wmain+0C9h (411B49h)
00411B34 push 1
00411B36 mov ecx,dword ptr [ebp-0ECh]
00411B3C call Test::`scalar deleting destructor' (41125Dh)
00411B41 mov dword ptr [ebp-10Ch],eax
00411B47 jmp wmain+0D3h (411B53h)
00411B49 mov dword ptr [ebp-10Ch],0
代码 Test::`scalar deleting destructor'其实是调用析构函数并释放空间的功能。
call Test::~Test () // 调用类的析构函数 ....... call operator delete () //这里由编译器负责调用了operator delete
对象数组的创建
Test* p1 = new Test[10]; 004115E3 push 0Eh 004115E5 call operator new[] (4110F0h) //负责对象的空间申请 004115EA add esp,4 004115ED mov dword ptr [ebp-104h],eax 004115F3 mov dword ptr [ebp-4],1 004115FA cmp dword ptr [ebp-104h],0 00411601 je wmain+12Dh (41163Dh) 00411603 mov eax,dword ptr [ebp-104h] 00411609 mov dword ptr [eax],0Ah 0041160F push offset Test::~Test (41107Dh) //析构函数地址 00411614 push offset Test::Test (4111EAh) //构造函数地址 00411619 push 0Ah 0041161B push 1 0041161D mov ecx,dword ptr [ebp-104h] 00411623 add ecx,4 00411626 push ecx 00411627 call `eh vector constructor iterator' (41119Ah) //对10个对象依次调用构造函数 0041162C mov edx,dword ptr [ebp-104h] 00411632 add edx,4 00411635 mov dword ptr [ebp-148h],edx 0041163B jmp wmain+137h (411647h) 0041163D mov dword ptr [ebp-148h],0 00411647 mov eax,dword ptr [ebp-148h] 0041164D mov dword ptr [ebp-110h],eax 00411653 mov dword ptr [ebp-4],0FFFFFFFFh 0041165A mov ecx,dword ptr [ebp-110h] 00411660 mov dword ptr [ebp-20h],ecx
对象数组的申请释放:
delete []p1;
00411663 mov eax,dword ptr [ebp-20h]
00411666 mov dword ptr [ebp-0ECh],eax
0041166C mov ecx,dword ptr [ebp-0ECh]
00411672 mov dword ptr [ebp-0F8h],ecx
00411678 cmp dword ptr [ebp-0F8h],0
0041167F je wmain+186h (411696h)
00411681 push 3
00411683 mov ecx,dword ptr [ebp-0F8h]
00411689 call Test::`vector deleting destructor' (41105Ah)//对10个对象依次调用析构函数
0041168E mov dword ptr [ebp-148h],eax
00411694 jmp wmain+190h (4116A0h)
00411696 mov dword ptr [ebp-148h],0
1