C++默认构造函数和空类大小

经常会看到这样一些观点,一个空的类,在没有构造函数的时候,生成一个实例,会调用自动生成的构造?会调用默认生成的无用构造?等一些回答。一个空类的实例大小为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 

调用了编译器给生成的构造函数。

上一篇:车位锁程序


下一篇:搬运1:关于对C语言中数组名取地址加减等操作的一点探究