一:背景
最近发现 C++ 中的类型初始化操作,没有 {}
运算符搞不定的,蛮有意思,今天我们就来逐一列一下各自的用法以及汇编展现,本来想分为 值类型
和 引用类型
两大块,但发现在 C++ 中没这种说法,默认都是 值类型
😂😂😂
二:各种玩法一览
1. int 上的初始化
首先看一下代码:
int main() { int i = { 10 }; int j{ 10 }; printf("i=%d, j=%d", i, j); }
相比C#来说,不带 =
的写法感觉还是怪怪的。。。 接下来看下对应的汇编代码。
int i = { 10 }; 00021825 mov dword ptr [ebp-8],0Ah int j{ 10 }; 0002182C mov dword ptr [ebp-14h],0Ah
从汇编代码看,就是一个简单的 栈赋值
,所以在 int 上用 {}
完全没必要,太伤键盘了。
2. 数组的初始化
继续看例子。
int main() { int num[] = { 10,11,12 }; }
这种写法中规中矩,基本上 C 系列的语言都这样,对于玩 C# 的我来说,不陌生。。。 不过人家默认是值类型,C# 是引用类型,从汇编代码中也能看的出来。
int num[] = { 10,11,12 }; 009C1E95 mov dword ptr [ebp-10h],0Ah 009C1E9C mov dword ptr [ebp-0Ch],0Bh 009C1EA3 mov dword ptr [ebp-8],0Ch
3. 结构体的初始化
结构体大家都很熟悉,直接上代码了。
typedef struct _Point { int x; int y; } Point; int main() { Point point = { 10,20 }; }
接下来看一下汇编代码。
Point point = { 10,20 }; 00481825 mov dword ptr [ebp-0Ch],0Ah 0048182C mov dword ptr [ebp-8],14h
可以看到,其实也是一组简单的赋值操作,很方便。
4. 类的初始化
方便讲述,先上代码:
class Location { private: int x; int y; int z; public: Location(int x, int y, int z) :x(x), y(y), z(z) { } }; int main() { Location location = { 10,11,12 }; }
接下来看下汇编代码,是不是调用了 Location 的构造函数。
Location location = { 10,11,12 }; 008D183F push 0Ch 008D1841 push 0Bh 008D1843 push 0Ah 008D1845 lea ecx,[ebp-14h] 008D1848 call Location::Location (08D13A7h)
可以看到确实调用了 构造函数,那个 ecx 就是 location 的 this 指针。
5. initializer_list 模板类
C++ 中的 initializer_list 类可以接收 {}
初始化语法作为初始化操作,这个有一点像 C# 的 param
可选参数,接下来把上例的中构造函数改成 initializer_list
来接收,代码如下:
class Location { public: int x; int y; int z; public: Location(initializer_list<int> list) { x = *(const_cast<int*>(list.begin())); y = *(const_cast<int*>(list.begin() + 1)); z = *(const_cast<int*>(list.begin() + 2)); } }; int main() { Location loc = { 10,11,12 }; printf("loc.x=%d,loc.y=%d,loc.z=%d", loc.x, loc.y, loc.z); }
接下来看下汇编代码。
Location loc = { 10,11,12 }; 00B9518F mov dword ptr [ebp-0F8h],0Ah 00B95199 mov dword ptr [ebp-0F4h],0Bh 00B951A3 mov dword ptr [ebp-0F0h],0Ch 00B951AD lea eax,[ebp-0ECh] 00B951B3 push eax 00B951B4 lea ecx,[ebp-0F8h] 00B951BA push ecx 00B951BB lea ecx,[ebp-0E4h] 00B951C1 call std::initializer_list<int>::initializer_list<int> (0B913C5h) 00B951C6 mov edx,dword ptr [eax+4] 00B951C9 push edx 00B951CA mov eax,dword ptr [eax] 00B951CC push eax 00B951CD lea ecx,[loc] 00B951D0 call Location::Location (0B913ACh)
从汇编代码看,它首先做了 initializer_list
的初始化操作,然后将弄好的集合丢到 Location
构造函数中,反转过来大概就是这样。
int main() { initializer_list<int> list = { 10,11,12 }; Location loc = { list }; printf("output: loc.x=%d,loc.y=%d,loc.z=%d", loc.x, loc.y, loc.z); }
哈哈,是不是感觉 {}
在初始化方面无所不能,好了,本篇就聊到这里了。