c++ 简单对象的内存分配过程
来源:互联网 发布:通达即时通讯端口 编辑:程序博客网 时间:2024/05/30 02:52
</pre><h3></h3><h3><strong></strong><pre name="code" class="cpp">#include<iostream>#include"stde.h"using namespace std;void ff_j_x(){char ss[10] = "dsfg";stde d(10, ss);d.shuchu();cout << &d<<&ss << endl;}int main(){ff_j_x();getchar();return 0;}//stde.h#pragma onceclass stde{ public:stde();stde(int, char*);~stde();void shuchu(); private:int age;char name[20];};//stde.cpp:#include "stde.h"#include<string.h>#include<iostream>using namespace std;stde::stde() :age(0){}stde::stde(int age, char* nname){strcpy_s(name, nname);this->age = age;}stde::~stde(){cout << "xi gou han shu!" << endl;}void stde::shuchu(){cout << this->age << this->name << endl;}
//调用函数ff_j_x在栈中创建(局部变量)对象d;调用其构造函数,输出函数。
<pre name="code" class="cpp">vs2013下反汇编:
void ff_j_x()
{
00A562A1 sub esp,0F8h
00A562A7 push ebx
00A562A8 push esi
00A562A9 push edi
00A562AA lea edi,[ebp-104h]
00A562B0 mov ecx,3Eh
00A562B5 mov eax,0CCCCCCCCh
00A562BA rep stos dword ptr es:[edi]
00A562BC mov eax,dword ptr ds:[00A60000h]
00A562C1 xor eax,ebp
00A562C3 mov dword ptr [ebp-10h],eax
00A562C6 push eax
00A562C7 lea eax,[ebp-0Ch]
00A562CA mov dword ptr fs:[00000000h],eax
char ss[10] = "dsfg";
00A562D0 mov eax,dword ptr ds:[00A5DDA8h] //(内存中)00A5DDA8h A8 64 73 66 67 00 00 00 00 28 00 dsfg....(.
00A562D5 mov dword ptr [ss],eax //dsfg占4字节内存 (dword ptr ) 把dsfg存入数组
00A562D8 mov cl,byte ptr ds:[0A5DDACh]
00A562DE mov byte ptr [ebp-1Ch],cl //dsfg后面补'\0'
00A562E1 xor eax,eax
00A562E3 mov dword ptr [ebp-1Bh],eax
00A562E6 mov byte ptr [ebp-17h],al //其余空间置0
stde d(10, ss);
00A562E9 lea eax,[ss] //参数ss进栈
00A562EC push eax //
00A562ED push 0Ah //参数10进栈
00A562EF lea ecx,[d] //取对象d的首地址存入ecx(即传入this指针)>>>>>(由此可知this指针不占内存)
00A562F2 call stde::stde (0A513EDh) //调用类的构造函数
00A562F7 mov dword ptr [ebp-4],0
d.shuchu();
00A562FE lea ecx,[d] //传入this指针
00A56301 call stde::shuchu (0A5145Bh) //调用类的输出函数
cout << &d<<&ss << endl;
00A56306 mov esi,esp
cout << &d<<&ss << endl;
00A56308 push 0A513FCh
00A5630D mov edi,esp
00A5630F lea eax,[ss] //取ss的首地址存入eax寄存器
00A56312 push eax //ss首地址进栈
00A56313 mov ebx,esp
00A56315 lea ecx,[d] //取d的首地址存入ecx寄存器(this指针)
00A56318 push ecx //d的首地址进栈
00A56319 mov ecx,dword ptr ds:[0A610A0h]
00A5631F call dword ptr ds:[0A61100h]
00A56325 cmp ebx,esp
00A56327 call __RTC_CheckEsp (0A51343h)
00A5632C mov ecx,eax
00A5632E call dword ptr ds:[0A61100h]
00A56334 cmp edi,esp
00A56336 call __RTC_CheckEsp (0A51343h)
00A5633B mov ecx,eax
00A5633D call dword ptr ds:[0A61090h]
00A56343 cmp esi,esp
00A56345 call __RTC_CheckEsp (0A51343h)
}
00A5634A mov dword ptr [ebp-4],0FFFFFFFFh
00A56351 lea ecx,[d] //传递this指针
00A56354 call stde::~stde (0A511F4h) //调用析构函数
00A56359 push edx
00A5635A mov ecx,ebp
00A5635C push eax
00A5635D lea edx,ds:[0A56394h]
00A56363 call @_RTC_CheckStackVars@8 (0A51136h)
00A56368 pop eax
00A56369 pop edx
00A5636A mov ecx,dword ptr [ebp-0Ch]
00A5636D mov dword ptr fs:[0],ecx
00A56374 pop ecx
00A56375 pop edi
00A56376 pop esi
00A56377 pop ebx
00A56378 mov ecx,dword ptr [ebp-10h]
00A5637B xor ecx,ebp
00A5637D call @__security_check_cookie@4 (0A51041h)
00A56382 add esp,104h
00A56388 cmp ebp,esp
00A5638A call __RTC_CheckEsp (0A51343h)
00A5638F mov esp,ebp
00A56391 pop ebp
00A56392 ret
00A56393 nop
00A56394 add al,byte ptr [eax]
00A56396 add byte ptr [eax],al
00A56398 pushfd
00A56399 arpl word ptr [ebp-2000h],sp
00A5639F dec dword ptr [edx]
00A563A1 add byte ptr [eax],al
00A563A3 add byte ptr [esi-3FFF5A9Dh],dh
00A563A9 ?? ??
00A563AA ?? ??
00A563AB call fword ptr [eax]
00A563AD add byte ptr [eax],al
00A563AF add byte ptr [ebx+6400A5h],dh
00A563B6 jae std::uncaught_exception+1h (0A5642Bh)
00A563B8 add ah,cl
构造函数的调用过程:
stde::stde(int age, char* nname)
{
00A53E0C push ecx //ecx存放有this指针 (由 void ff_j_x() 函数的 00F2630F lea ecx,[d] 可知)
00A53E0D lea edi,[ebp-0CCh]
00A53E13 mov ecx,33h
00A53E18 mov eax,0CCCCCCCCh //33*4=cch字节空间初始化为值cc
00A53E1D rep stos dword ptr es:[edi]
00A53E1F pop ecx
00A53E20 mov dword ptr [this],ecx //保存ecx的值到this指针
strcpy_s(name, nname);
00A53E23 mov eax,dword ptr [nname]
00A53E26 push eax
00A53E27 mov ecx,dword ptr [this]
00A53E2A add ecx,4
00A53E2D push ecx
00A53E2E call strcpy_s<20> (0A51069h)
00A53E33 add esp,8
this->age = age;
00A53E36 mov eax,dword ptr [this]
00A53E39 mov ecx,dword ptr [age]
00A53E3C mov dword ptr [eax],ecx
}
00A53E3E mov eax,dword ptr [this]
00A53E41 pop edi
00A53E42 pop esi
00A53E43 pop ebx
00A53E44 add esp,0CCh
00A53E4A cmp ebp,esp
00A53E4C call __RTC_CheckEsp (0A51343h)
00A53E51 mov esp,ebp
00A53E53 pop ebp
00A53E54 ret 8
第一次调试:
+ss0x0035f9cc "dsfg"char[10]
+d{age=-858993460 name=0x0035f9b0 "烫烫烫烫烫烫烫烫烫烫 }stde
&d=0x0035f9b0-4=0x0035f9ac
ECX?=?0035F9AC (d.age的地址)
ECX存放的是this指针, 说名this指针就是对象首元素的地址。
第二次调试:
+ss0x0045f744 "dsfg"char[10]
+d{age=-858993460 name=0x0045f728 "烫烫烫烫烫烫烫烫烫烫 }stde
&d=0x0045f724;
this==0x0045f724(即ECX=0x0045f724);
00A53E3E mov eax,dword ptr [this] //返回值存放在EAX寄存器 所以是返回this指针
(void ff_j_x()原函数没有返回值 但是this指针是默认返回的)
00A53E41 pop edi
00A53E42 pop esi
00A53E43 pop ebx
00A53E44 add esp,0CCh
00A53E4A cmp ebp,esp
00A53E4C call __RTC_CheckEsp (0A51343h)
00A56351 lea ecx,[d] //传递this指针
00A56354 call stde::~stde (0A511F4h) //调用析构函数
由于对象d是在ff_j_x()函数的栈空间中分配的,当ff_j_x()结束时,该函数的所有栈空间都被释放,
所以该函数在退出时会调用对象的析构函数来释放掉对象d,这是在编译的时候,编译器加上去的。
0x0045f724: 0a 00 00 00 64 73 66 67 00 fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe cc cc cc cc cc cc cc cc
这是对象d在栈中的存储情况; d.age=0x0000000a(十进制:10) d.name = 0x67667364(字符:dsfg)
说明对象的内存分配是先定义先分配
本例中:
private:int age;char name[20];age是先定义的 , name是最后定义的 , 所以创建对象时会先给age分配内存再给name分配内存。也就是说age的栈内存地址低于name的栈内存地址
0x0045f724:
(相对栈顶)
(低地址) 0a 00 00 00(age)64 73 66 67 00(name) fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe cc cc cc cc cc cccc cc(高地址)
(相对栈低)
下面用一段新代码进行该问题的讨论:
</pre><pre name="code" class="cpp"><pre name="code" class="cpp">//Abc.h#pragma onceclass Abc{public:Abc(int, int , int );void Show();~Abc();private:int x;int y;const int i;const int j;};//Abc.cpp#include "Abc.h"#include<iostream>using namespace std;Abc::Abc(int a, int b, int c) :j(a), i(j), y(x), x(b){}void Abc::Show(){cout <<"x = "<< x << " " <<"y = "<< y << " " <<"i = "<< i << " "<<"j = " << j << endl;}Abc::~Abc(){}void f(){Abc a(1, 2, 3);a.Show();}//main()#include "Abc.h"#include<iostream>using namespace std;int main(){f();getchar();return 0;}
//运行结果: x = 1 y = 1 i = -858993460 j = 2
证明 :j(a), i(j), y(x), x(b) 是先给x赋值x=b=1; 然后是y=x=1; 再到i=j=?;最后是j=a=2;
VS2013反汇编: void f() { 013E66C4 add byte ptr [eax-33333334h],bh 013E66CA rep stos dword ptr es:[edi] 013E66CC mov eax,dword ptr ds:[013F0000h] 013E66D1 xor eax,ebp 013E66D3 mov dword ptr [ebp-10h],eax 013E66D6 push eax 013E66D7 lea eax,[ebp-0Ch] 013E66DA mov dword ptr fs:[00000000h],eax Abc a(1, 2, 3); 013E66E0 push 3 013E66E2 push 2 013E66E4 push 1 013E66E6 lea ecx,[a] 013E66E9 call Abc::Abc (013E1046h) 013E66EE mov dword ptr [ebp-4],0 a.Show(); 013E66F5 lea ecx,[a] 013E66F8 call Abc::Show (013E105Ah) } Abc::Abc(int a, int b, int c) :j(b), i(j), y(x), x(a) { 013E3AD0 push ebp 013E3AD1 mov ebp,esp 013E3AD3 sub esp,0CCh 013E3AD9 push ebx 013E3ADA push esi 013E3ADB push edi 013E3ADC push ecx 013E3ADD lea edi,[ebp-0CCh] 013E3AE3 mov ecx,33h 013E3AE8 mov eax,0CCCCCCCCh 013E3AED rep stos dword ptr es:[edi] 013E3AEF pop ecx //this指针 013E3AF0 mov dword ptr [this],ecx
x(b):
013E3AF3 mov eax,dword ptr [this] //eax存放this指针
013E3AF6 mov ecx,dword ptr [b] //ecx存放a的值013E3AF9 mov dword ptr [eax],ecx //把a存入this指向的开始位置
y(x):
013E3AFB mov eax,dword ptr [this] //eax存放this指针013E3AFE mov ecx,dword ptr [this] //ecx存放this指针013E3B01 mov edx,dword ptr [ecx] //把ecx(即x的值)赋给edx013E3B03 mov dword ptr [eax+4],edx //edx赋值给this+4的地址空间(即y);
i(j):
013E3B06 mov eax,dword ptr [this] //this指针存入eax013E3B09 mov ecx,dword ptr [this] //this指针存入ecx013E3B0C mov edx,dword ptr [ecx+0Ch] //j的值赋值给edx013E3B0F mov dword ptr [eax+8],edx //edx赋值给i
j(a):
013E3B12 mov eax,dword ptr [this] //this指针存入eax
013E3B15 mov ecx,dword ptr [a] //形参b的值存入ecx013E3B18 mov dword ptr [eax+0Ch],ecx //ecx赋值给j}013E3B1B mov eax,dword ptr [this]
实验结果也证明了:
j(a), i(j), y(x), x(b) 是先给x赋值x=b=1; 然后是y=x=1; 再到i=j=?;最后是j=a=2;
编译环境:VS2013 2015/06/12
0 0
- c++ 简单对象的内存分配过程
- 创建string对象过程的内存分配
- 创建String对象过程的内存分配
- Java对象的内存分配过程
- String对象的创建过程中的内存分配
- String对象的创建过程中的内存分配
- 关于创建String对象过程的内存分配
- 关于创建String对象过程的内存分配
- 创建String对象过程的内存分配小结
- 关于创建String对象过程的内存分配
- Java创建对象过程中,内存的分配
- Java创建对象过程中,内存的分配
- JVM内存分配以及对象的创建过程
- 简单的内存分配
- C的内存分配
- 堆的内存结构,对象内存如何分配,GC过程对象的转移
- Objective-C中对象的初始化及内存分配
- C指针一个简单的小错误(1)-内存分配
- c++栈和队列
- 排列熵算法简介及c#实现
- iOS-项目开发,细节,报错,处理(1)
- java最基本的四个数据类型大小和范围
- VLC流程的分析
- c++ 简单对象的内存分配过程
- 牢记这20个不要,人生会更加精彩
- hiho第五周——数字三角形(动态规划)
- 【小技巧】SQLite语句设置 自动增长字段
- 算法之详解最小生成树
- view和viewgroup的详解
- Using JavaFX UI Controls 12 Table View
- 用C++解决:把数组排成最小的数问题
- Who's in the Middle