经常会看到这样一些观点,一个空的类,在没有构造函数的时候,生成一个实例,会调用自动生成的构造?会调用默认生成的无用构造?等一些回答。一个空类的实例大小为1,那一个字节又是什么?
struct TestStruct1 { }; int main() { TestStruct1 st1; cout << sizeof(st1); }
现有一段代码和对应的汇编代码
TestStruct1 st1; cout << sizeof(st1); 000A284F mov esi,esp 000A2851 push 1 000A2853 mov ecx,dword ptr ds:[000AD0CCh] 000A2859 call dword ptr ds:[000AD09Ch] 000A285F cmp esi,esp 000A2861 call 000A12F3
会发现生成st1实例的时候没有任何操作,在打印实例大小的时候直接把1传入打印函数。
TestStruct1 *st=new TestStruct1();
cout << sizeof(*st);
在栈里生成实例,该实例的地址为...;那接下来,我们在堆里生成一个实例和对应的汇编代码。
000A2866 push 1 000A2868 call 000A1145 000A286D add esp,4 000A2870 mov dword ptr [ebp+FFFFFF10h],eax 000A2876 cmp dword ptr [ebp+FFFFFF10h],0 000A287D je 000A288D 000A287F mov eax,dword ptr [ebp+FFFFFF10h] 000A2885 mov dword ptr [ebp+FFFFFF08h],eax 000A288B jmp 000A2897 000A288D mov dword ptr [ebp+FFFFFF08h],0 000A2897 mov ecx,dword ptr [ebp+FFFFFF08h] 000A289D mov dword ptr [ebp-18h],ecx cout << sizeof(*st); 000A28A0 mov esi,esp 000A28A2 push 1 000A28A4 mov ecx,dword ptr ds:[000AD0CCh] 000A28AA call dword ptr ds:[000AD09Ch] 000A28B0 cmp esi,esp 000A28B2 call 000A12F3
在堆里生成的实例有地址,0x015FB018(每一次运行地址都不一样),因为它的大小只有一个字节,我们根据内存地址找到后存的是cd,转十进制205,我运行过多次,都是205。
接下来上一个给了构造函数例子:
struct TestStruct2 { TestStruct2() {}; }; TestStruct2 st2; cout << sizeof(st2); TestStruct2* st3 = new TestStruct2(); cout << sizeof(*st3);
对应的汇编代码;
0078678F lea ecx,[ebp-2Dh] 00786792 call 007814DD cout << sizeof(st2); 00786797 mov esi,esp 00786799 push 1 0078679B mov ecx,dword ptr ds:[0078D0CCh] 007867A1 call dword ptr ds:[0078D09Ch] 007867A7 cmp esi,esp 007867A9 call 007812F3 TestStruct2* st3 = new TestStruct2(); 007867AE push 1 007867B0 call 00781145 007867B5 add esp,4 007867B8 mov dword ptr [ebp+FFFFFEE0h],eax 007867BE mov dword ptr [ebp-4],0 007867C5 cmp dword ptr [ebp+FFFFFEE0h],0 007867CC je 007867E1 007867CE mov ecx,dword ptr [ebp+FFFFFEE0h] 007867D4 call 007814DD 007867D9 mov dword ptr [ebp+FFFFFED8h],eax 007867DF jmp 007867EB 007867E1 mov dword ptr [ebp+FFFFFED8h],0 007867EB mov eax,dword ptr [ebp+FFFFFED8h] 007867F1 mov dword ptr [ebp+FFFFFEECh],eax 007867F7 mov dword ptr [ebp-4],0FFFFFFFFh 007867FE mov ecx,dword ptr [ebp+FFFFFEECh] 00786804 mov dword ptr [ebp-3Ch],ecx cout << sizeof(*st3); 00786807 mov esi,esp 00786809 push 1 0078680B mov ecx,dword ptr ds:[0078D0CCh] 00786811 call dword ptr ds:[0078D09Ch] 00786817 cmp esi,esp 00786819 call 007812F3
子啊有构造函数的时候我们可以看到Call了我们给的构造函数。
同时也总结出:在我们没有给构造函数的时候,编译器不一定会自动给生成构造函数。
struct TestStruct1 { int i=1; }; TestStruct1 st1; cout << sizeof(st1); TestStruct1 *st=new TestStruct1(); cout << sizeof(*st);
当我们在类里声明一个变量并给它赋值的时候,这个时候的汇编代码:
TestStruct1 st1; 00296727 lea ecx,[ebp-18h] 0029672A call 002914E7 cout << sizeof(st1); 0029672F mov esi,esp 00296731 push 4 00296733 mov ecx,dword ptr ds:[0029D0CCh] 00296739 call dword ptr ds:[0029D09Ch] 0029673F cmp esi,esp 00296741 call 002912F3
调用了编译器给生成的构造函数。