C++ 内存分配(new,operator new)面面观 (二)

2014-11-23 23:33:58 · 作者: · 浏览: 26
1081 push eax
01301082 call std::operator<< > (13011F0h)
01301087 add esp,8
0130108A mov ecx,eax
0130108C call dword ptr [__imp_std::basic_ostream >::operator<< (1302040h)]
01301092 push esi ;压入a
01301093 call operator delete (13013BCh) ;调用operator delete
01301098 add esp,4
通过反汇编可以看出A* = new A包含了operator new(sizeof(A))和A()两个步骤(当然,最后还要将值返回到a)
delete a包含了~A()和operator delete(a)两个步骤。

A* a = new A;
01301022 push 1 ;不含数据成员的类占用一字节空间,此处压入sizeof(A)
01301024 call operator new (13013C2h) ;调用operator new(size_t size)
01301029 mov esi,eax ;返回值保存到esi
0130102B add esp,4 ;平衡栈
0130102E mov dword ptr [esp+8],esi ;
01301032 mov dword ptr [esp+14h],0
0130103A test esi,esi ;在operator new之后,检查其返回值,如果为空(分配失败),则不调用A()构造函数
0130103C je wmain+62h (1301062h) ;为空 跳过构造函数部分
0130103E mov eax,dword ptr [__imp_std::endl (1302038h)] ;构造函数内部,输出字符串
01301043 mov ecx,dword ptr [__imp_std::cout (1302050h)]
01301049 push eax
0130104A push offset string "call A constructor" (1302134h)
0130104F push ecx
01301050 call std::operator<< > (13011F0h)
01301055 add esp,8
01301058 mov ecx,eax
0130105A call dword ptr [__imp_std::basic_ostream >::operator<< (1302040h)]
01301060 jmp wmain+64h (1301064h) ;构造完成,跳过下一句
01301062 xor esi,esi ;将esi置空,这里的esi即为new A的返回值
01301064 mov dword ptr [esp+14h],0FFFFFFFFh
delete a;
0130106C test esi,esi ;检查a是否为空
0130106E je wmain+9Bh (130109Bh) ;如果为空,跳过析构函数和operator delete
01301070 mov edx,dword ptr [__imp_std::endl (1302038h)] ;析构函数 输出字符串
01301076 mov eax,dword ptr [__imp_std::cout (1302050h)]
0130107B push edx
0130107C push offset string "call A destructor" (1302148h)
01301081 push eax
01301082 call std::operator<< > (13011F0h)
01301087 add esp,8
0130108A mov ecx,eax
0130108C call dword ptr [__imp_std::basic_ostream >::operator<< (1302040h)]
01301092 push esi ;压入a
01301093 call operator delete (13013BCh) ;调用operator delete
01301098 add esp,4
通过反汇编可以看出A* = new A包含了operator new(sizeof(A))和A()两个步骤(当然,最后还要将值返回到a)
delete a包含了~A()和operator delete(a)两个步骤。

二 operator new的三种形式:
operator new有三种形式:
throwing (1) void* operator new (std::size_t size) throw (std::bad_alloc);

nothrow (2) void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw();

placement (3) void* operator new (std::size_t size, void* ptr) throw();

(1)(2)的区别仅是是否抛出异常,当分配失败时,前者会抛出bad_alloc异常,后者返回null,不会抛出异常。它们都分配一个固定大小的连续内存。
用法示例:
A* a = new A; //调用throwing(1)
A* a = new(std::nothrow) A; //调用nothrow(2)
(3)是placement new,它也是对operator new的一个重载,定义于中,它多接收一个ptr参数,但它只是简单地返回ptr。其在new.h下的源代码如下:
[cpp]
#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
inline void *__cdecl operator new(size_t, void *_P)
{return (_P); }
#if _MSC_VER >= 1200
inline void __cdecl operator delete(void *, void *)
{return; }
#endif
#endif

#ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
inline void *__cdecl operator new(size_t, void *_P)
{return (_P); }
#if _MSC_VER >= 1200
inline void __cdecl operator delete(void *, void *)
{return;