今天做了个小试验,类成员变量的初始化,发现放在参数列表和构造函数体内是一样的
好久没来了,准备毕业、毕业答辩、毕业、找工作、现在终于稳定下来。突然想到一个问题,随便测试下写写,不要拍砖哈
编译器:VC2005 Release模式,代码不优化
调试器: OllyDBG 1.10
程序如下:
class
A
{
public:
A();
~A();
int a;
long b;
} ;
class B
{
public:
B();
~B();
int a;
long b;
} ;
A::A() : a( 0 )
,b( - 1 )
{
}
A:: ~ A()
{
}
B::B()
{
a = 1;
b = -2;
}
B:: ~ B()
{
}
int main()
{
__asm
{
push eax //加些标记,方便辨认
add esp,4
}
A a;
__asm
{
push ebx //加些标记,方便辨认
push ebx
add esp,8
}
B b;
return 0;
}
{
public:
A();
~A();
int a;
long b;
} ;
class B
{
public:
B();
~B();
int a;
long b;
} ;
A::A() : a( 0 )
,b( - 1 )
{
}
A:: ~ A()
{
}
B::B()
{
a = 1;
b = -2;
}
B:: ~ B()
{
}
int main()
{
__asm
{
push eax //加些标记,方便辨认
add esp,4
}
A a;
__asm
{
push ebx //加些标记,方便辨认
push ebx
add esp,8
}
B b;
return 0;
}
对应的汇编及分析如下:
对应的汇编及分析如下:
对应的汇编及分析如下:
// 类A的构造函数
00401000 / $ 55 push ebp // 将当前栈基址压栈保存
00401001 | . 8BEC mov ebp, esp // 将当前栈指针作为栈基址
00401003 | . 51 push ecx // this指针压栈
00401004 | . 894D FC mov dword ptr [ebp - 4 ], ecx // 保存this指针
00401007 | . 8B45 FC mov eax, dword ptr [ebp - 4 ] // this指针放入eax
0040100A | . C700 00000000 mov dword ptr [eax], 0 // this指针指向的地址存入0,也就是变量a,对应语句*(int*)this=0;
00401010 | . 8B4D FC mov ecx, dword ptr [ebp - 4 ] // this指针放入ecx(多余的一步)
00401013 | . C741 04 FFFFF > mov dword ptr [ecx + 4 ], - 1 // this指针指向的地址存入-1,也就是变量b,对应语句*(int*)(this+4)=-1;
0040101A | . 8B45 FC mov eax, dword ptr [ebp - 4 ] // 返回值放入eax
0040101D | . 8BE5 mov esp, ebp // 还原先前的esp、ebp
0040101F | . 5D pop ebp
00401020 \. C3 retn
// 中间代码省略
// 类B的构造函数,和a的一模一样
00401030 / $ 55 push ebp
00401031 | . 8BEC mov ebp, esp
00401033 | . 51 push ecx
00401034 | . 894D FC mov dword ptr [ebp - 4 ], ecx
00401037 | . 8B45 FC mov eax, dword ptr [ebp - 4 ]
0040103A | . C700 01000000 mov dword ptr [eax], 1
00401040 | . 8B4D FC mov ecx, dword ptr [ebp - 4 ]
00401043 | . C741 04 FEFFF > mov dword ptr [ecx + 4 ], - 2
0040104A | . 8B45 FC mov eax, dword ptr [ebp - 4 ]
0040104D | . 8BE5 mov esp, ebp
0040104F | . 5D pop ebp
00401050 \. C3 retn
// 中间代码省略
// 2个类公用一个析构函数
00401060 / $ 55 push ebp
00401061 | . 8BEC mov ebp, esp
00401063 | . 51 push ecx
00401064 | . 894D FC mov dword ptr [ebp - 4 ], ecx
00401067 | . 8BE5 mov esp, ebp
00401069 | . 5D pop ebp
0040106A \. C3 retn
// 中间代码省略
// main()函数
00401070 / $ 55 push ebp
00401071 | . 8BEC mov ebp, esp
00401073 | . 83EC 14 sub esp, 14 // 给变量分配20字节空间
00401076 | . 50 push eax // 刚才的代码标记
00401077 | . 83C4 04 add esp, 4 // 刚才的代码标记
0040107A | . 8D4D F8 lea ecx, dword ptr [ebp - 8 ] // thiscall调用约定,this指针通过ecx传递
0040107D | . E8 7EFFFFFF call 00401000 // 调用A构造函数
00401082 | . 53 push ebx // 刚才的代码标记
00401083 | . 53 push ebx // 刚才的代码标记
00401084 | . 83C4 08 add esp, 8 // 刚才的代码标记
00401087 | . 8D4D F0 lea ecx, dword ptr [ebp - 10 ] // thiscall调用约定,this指针通过ecx传递
0040108A | . E8 A1FFFFFF call 00401030 // 调用B构造函数
0040108F | . C745 EC 00000 > mov dword ptr [ebp - 14 ], 0 // 函数返回值预先存储好
00401096 | . 8D4D F0 lea ecx, dword ptr [ebp - 10 ]
00401099 | . E8 C2FFFFFF call 00401060 // 调用B析构函数
0040109E | . 8D4D F8 lea ecx, dword ptr [ebp - 8 ]
004010A1 | . E8 BAFFFFFF call 00401060 // 调用A析构函数
004010A6 | . 8B45 EC mov eax, dword ptr [ebp - 14 ] // 返回值最后放入eax
004010A9 | . 8BE5 mov esp, ebp
004010AB | . 5D pop ebp
004010AC \. C3 retn
// 类A的构造函数
00401000 / $ 55 push ebp // 将当前栈基址压栈保存
00401001 | . 8BEC mov ebp, esp // 将当前栈指针作为栈基址
00401003 | . 51 push ecx // this指针压栈
00401004 | . 894D FC mov dword ptr [ebp - 4 ], ecx // 保存this指针
00401007 | . 8B45 FC mov eax, dword ptr [ebp - 4 ] // this指针放入eax
0040100A | . C700 00000000 mov dword ptr [eax], 0 // this指针指向的地址存入0,也就是变量a,对应语句*(int*)this=0;
00401010 | . 8B4D FC mov ecx, dword ptr [ebp - 4 ] // this指针放入ecx(多余的一步)
00401013 | . C741 04 FFFFF > mov dword ptr [ecx + 4 ], - 1 // this指针指向的地址存入-1,也就是变量b,对应语句*(int*)(this+4)=-1;
0040101A | . 8B45 FC mov eax, dword ptr [ebp - 4 ] // 返回值放入eax
0040101D | . 8BE5 mov esp, ebp // 还原先前的esp、ebp
0040101F | . 5D pop ebp
00401020 \. C3 retn
// 中间代码省略
// 类B的构造函数,和a的一模一样
00401030 / $ 55 push ebp
00401031 | . 8BEC mov ebp, esp
00401033 | . 51 push ecx
00401034 | . 894D FC mov dword ptr [ebp - 4 ], ecx
00401037 | . 8B45 FC mov eax, dword ptr [ebp - 4 ]
0040103A | . C700 01000000 mov dword ptr [eax], 1
00401040 | . 8B4D FC mov ecx, dword ptr [ebp - 4 ]
00401043 | . C741 04 FEFFF > mov dword ptr [ecx + 4 ], - 2
0040104A | . 8B45 FC mov eax, dword ptr [ebp - 4 ]
0040104D | . 8BE5 mov esp, ebp
0040104F | . 5D pop ebp
00401050 \. C3 retn
// 中间代码省略
// 2个类公用一个析构函数
00401060 / $ 55 push ebp
00401061 | . 8BEC mov ebp, esp
00401063 | . 51 push ecx
00401064 | . 894D FC mov dword ptr [ebp - 4 ], ecx
00401067 | . 8BE5 mov esp, ebp
00401069 | . 5D pop ebp
0040106A \. C3 retn
// 中间代码省略
// main()函数
00401070 / $ 55 push ebp
00401071 | . 8BEC mov ebp, esp
00401073 | . 83EC 14 sub esp, 14 // 给变量分配20字节空间
00401076 | . 50 push eax // 刚才的代码标记
00401077 | . 83C4 04 add esp, 4 // 刚才的代码标记
0040107A | . 8D4D F8 lea ecx, dword ptr [ebp - 8 ] // thiscall调用约定,this指针通过ecx传递
0040107D | . E8 7EFFFFFF call 00401000 // 调用A构造函数
00401082 | . 53 push ebx // 刚才的代码标记
00401083 | . 53 push ebx // 刚才的代码标记
00401084 | . 83C4 08 add esp, 8 // 刚才的代码标记
00401087 | . 8D4D F0 lea ecx, dword ptr [ebp - 10 ] // thiscall调用约定,this指针通过ecx传递
0040108A | . E8 A1FFFFFF call 00401030 // 调用B构造函数
0040108F | . C745 EC 00000 > mov dword ptr [ebp - 14 ], 0 // 函数返回值预先存储好
00401096 | . 8D4D F0 lea ecx, dword ptr [ebp - 10 ]
00401099 | . E8 C2FFFFFF call 00401060 // 调用B析构函数
0040109E | . 8D4D F8 lea ecx, dword ptr [ebp - 8 ]
004010A1 | . E8 BAFFFFFF call 00401060 // 调用A析构函数
004010A6 | . 8B45 EC mov eax, dword ptr [ebp - 14 ] // 返回值最后放入eax
004010A9 | . 8BE5 mov esp, ebp
004010AB | . 5D pop ebp
004010AC \. C3 retn
由此可见,成员变量放在初始化列表和构造函数体内,汇编代码是一样的,也就是不管放在那里,是没有差别的