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


    一:背景

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

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

    图片名称
  • 相关阅读:
    Maven使用教程
    [转载]DIV CSS设计时IE6、IE7、FF 与兼容性有关的特性
    ASP.NET MVC 开篇
    基于WebForm+EasyUI的业务管理系统形成之旅 -- ParamQueryGrid行、列合并(Ⅸ)
    基于WebForm+EasyUI的业务管理系统形成之旅 -- 施工计划查询(Ⅷ)
    浅析WCF与WebService、WPF与Silverlight 区别
    LeetCode-3Sum Smaller
    LeetCode-Different Ways to Add Parentheses
    LeetCode-Count Univalue Subtrees
    LeetCode-Decode String
  • 原文地址:https://www.cnblogs.com/huangxincheng/p/16465318.html
Copyright © 2020-2023  润新知