0

聊聊 C++ 大一统的初始化运算符 {}

 1 year ago
source link: https://www.cnblogs.com/huangxincheng/p/16465318.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近发现 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);
}

哈哈,是不是感觉 {} 在初始化方面无所不能,好了,本篇就聊到这里了。

图片名称

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK