[Mac 10.7.1 Lion Intel-based x64 gcc4.2.1 xcode4.2]
Q: new操作符构造一个对象,它内部究竟调用了什么?
A: 如下代码:
#include <iostream> using namespace std; #define COUT_ENDL(str) std::cout << #str << " is " << (str) << std::endl; class A { public: A(int value_one, int value_two):_value_one(value_one), _value_two(value_two) { } int value_one() const { return _value_one; } int value_two() const { return _value_two; } virtual void show() const { std::cout << "show A..." << std::endl; } private: int _value_one; int _value_two; }; int main (int argc, const char * argv[]) { A *a = new A(1, 2); return 0; }
为了便于查看汇编,先不写delete释放代码了。main函数的汇编代码如下:
0x00001b50 <main+0>: push %ebp 0x00001b51 <main+1>: mov %esp,%ebp 0x00001b53 <main+3>: sub $0x28,%esp 0x00001b56 <main+6>: mov 0xc(%ebp),%eax 0x00001b59 <main+9>: mov 0x8(%ebp),%ecx 0x00001b5c <main+12>: mov %ecx,-0x4(%ebp) 0x00001b5f <main+15>: mov %eax,-0x8(%ebp) 0x00001b62 <main+18>: movl $0xc,(%esp) 0x00001b69 <main+25>: call 0x1dd4 <dyld_stub__Znwm> 0x00001b6e <main+30>: mov %eax,-0x14(%ebp) 0x00001b71 <main+33>: mov -0x14(%ebp),%eax 0x00001b74 <main+36>: mov %eax,(%esp) 0x00001b77 <main+39>: movl $0x1,0x4(%esp) 0x00001b7f <main+47>: movl $0x2,0x8(%esp) 0x00001b87 <main+55>: call 0x1c68 <_ZN1AC1Eii> 0x00001b8c <main+60>: mov -0x14(%ebp),%eax 0x00001b8f <main+63>: mov %eax,-0x18(%ebp) 0x00001b92 <main+66>: movl $0x0,-0x10(%ebp) 0x00001b99 <main+73>: mov -0x10(%ebp),%eax 0x00001b9c <main+76>: mov %eax,-0xc(%ebp) 0x00001b9f <main+79>: mov -0xc(%ebp),%eax 0x00001ba2 <main+82>: add $0x28,%esp 0x00001ba5 <main+85>: pop %ebp 0x00001ba6 <main+86>: ret
使用idaq工具打开/usr/lib/libstdc++.6.dylib文件,寻找operator new函数的位置。
可以看得出来,它和call指令对应的__Znwm是对应的。
上面汇编代码的第二个call指令,正是类A的构造函数。这个可以在类A的构造函数处加断点,进入后,反汇编得到此函数的内部名称,和call对应的名称是一致的。
同时,对于operator new的内部,可以发现它会调用malloc函数,如果失败,便会抛出异常。
Q: 这么说来,上面的代码中调用的new可以分为两步来做?
A: 是的。如下代码:
int main (int argc, const char * argv[]) { void *mem = operator new(sizeof(A)); // alloc a mem A *a = new (mem) A(1, 2); // call construct function in mem delete a; return 0; }
Q: operator new函数是否可以重载?
A: 是的。
void * operator new(size_t size) { std::cout << "operator new is called..." << std::endl; return malloc(size); } int main (int argc, const char * argv[]) { void *mem = operator new(sizeof(A)); // alloc a mem A *a = new (mem) A(1, 2); // call construct function in mem delete a; return 0; }
operator new is called...
Q: 可以在类中重载new操作符吗?
A: 是的。
#include <iostream> using namespace std; #define COUT_ENDL(str) std::cout << #str << " is " << (str) << std::endl; class A { public: A(int value_one, int value_two):_value_one(value_one), _value_two(value_two) { } int value_one() const { return _value_one; } int value_two() const { return _value_two; } virtual void show() const { std::cout << "show A..." << std::endl; } void * operator new(size_t size) { std::cout << "operator new is called..." << std::endl; return malloc(size); } private: int _value_one; int _value_two; }; class B { }; int main (int argc, const char * argv[]) { A *a = new A(1, 2); delete a; B *b = new B; delete b; return 0; }
operator new is called...
Q: A *a = new A(1, 2); 和 A a1(1, 2); 这两句代码有什么不同呢?
A: 如下代码:
int main (int argc, const char * argv[]) { A *a = new A(1, 2); A a1(1, 2); delete a; return 0; }
0x00001a70 <main+0>: push %ebp 0x00001a71 <main+1>: mov %esp,%ebp 0x00001a73 <main+3>: sub $0x38,%esp 0x00001a76 <main+6>: mov 0xc(%ebp),%eax 0x00001a79 <main+9>: mov 0x8(%ebp),%ecx 0x00001a7c <main+12>: mov %ecx,-0x4(%ebp) 0x00001a7f <main+15>: mov %eax,-0x8(%ebp) 0x00001a82 <main+18>: movl $0xc,(%esp) 0x00001a89 <main+25>: call 0x1c50 <_ZN1AnwEm> 0x00001a8e <main+30>: mov %eax,-0x14(%ebp) 0x00001a91 <main+33>: mov -0x14(%ebp),%eax 0x00001a94 <main+36>: mov %eax,(%esp) 0x00001a97 <main+39>: movl $0x1,0x4(%esp) 0x00001a9f <main+47>: movl $0x2,0x8(%esp) 0x00001aa7 <main+55>: call 0x1bb0 <_ZN1AC1Eii> 0x00001aac <main+60>: mov -0x14(%ebp),%eax 0x00001aaf <main+63>: mov %eax,-0x18(%ebp) 0x00001ab2 <main+66>: lea -0x28(%ebp),%eax 0x00001ab5 <main+69>: mov %eax,(%esp) 0x00001ab8 <main+72>: movl $0x1,0x4(%esp) 0x00001ac0 <main+80>: movl $0x2,0x8(%esp) 0x00001ac8 <main+88>: call 0x1bb0 <_ZN1AC1Eii> 0x00001acd <main+93>: mov -0x18(%ebp),%eax 0x00001ad0 <main+96>: mov %eax,(%esp) 0x00001ad3 <main+99>: call 0x1d94 <dyld_stub__ZdlPv> 0x00001ad8 <main+104>: movl $0x0,-0x10(%ebp) 0x00001adf <main+111>: mov -0x10(%ebp),%eax 0x00001ae2 <main+114>: mov %eax,-0xc(%ebp) 0x00001ae5 <main+117>: mov -0xc(%ebp),%eax 0x00001ae8 <main+120>: add $0x38,%esp 0x00001aeb <main+123>: pop %ebp 0x00001aec <main+124>: ret
Q: 既然可以使用operator new单独申请空间,然后单独调用构造函数,那么可否单独调用析构函数,然后释放内存?
A: 是的。
#include <iostream> using namespace std; #define COUT_ENDL(str) std::cout << #str << " is " << (str) << std::endl; class A { public: A(int value_one, int value_two):_value_one(value_one), _value_two(value_two) { } int value_one() const { return _value_one; } int value_two() const { return _value_two; } virtual void show() const { std::cout << "show A..." << std::endl; } void * operator new(size_t size) { std::cout << "operator new is called..." << std::endl; return malloc(size); } void operator delete(void *p) { free(p); } private: int _value_one; int _value_two; }; int main (int argc, const char * argv[]) { A *a = new A(1, 2); a->A::~A(); // call deconstruct function free(a); // free the mem return 0; }
xichen
2012-6-2 22:59:05