C++11中列表初始化机制的概念与实例详解
概述
定义:列表初始化是C++11引入的新标准,目的是统一初始化方式
C++11以前只能使用列表初始化来初始化内置类型数组和POD类型对象,C++11中列表初始化可以用于初始化任何类型对象
- POD(plain old data)类型:仅由内置类型变量构成且不含指针的类,简单来说是可以直接使用memcpy复制的对象
- 聚合体(aggregate):聚合体一定是POD类型
- 无自定义构造函数
- 无私有或保护的非静态数据成员(静态成员与单独对象无关,故不影响初始化)
- 无基类
- 无虚函数
- 无类内已经初始化的非静态数据成员
注意:区分列表初始化和初始化列表
列表初始化:用{}进行初始化的方式
初始化列表:构造函数体前对对象成员直接进行初始化的列表
initializer_list:一种用于未定参数的轻量STL容器
实现机制详解
对内置类型对象、POD对象和类对象的列表初始化实现细节是不同的
POD类型的列表初始化
- 此处POD类型包括:内置类型、聚合体类
- 内置类型数组按照顺序初始化
- C++11标准中列表初始化会防止可能导致潜在信息丢失的类型缩小(即不能像赋值一样将大类型如int隐式转换成小类型如char)
- 聚合体类按照成员定义顺序依次初始化
含有构造函数的类的列表初始化(C++11)
- 通过{}进行初始化和()结果一致【即通过()调用构造函数的地方都可以完全等价地用{}代替】,都是直接用括号内的值调用对应构造函数直接初始化对象,并不会先生成临时对象再拷贝
- ={}与{}是等价的语法【即加不加=对初始化行为没有影响】,均不会调用拷贝运算符或拷贝构造函数
- 与内置类型的列表初始化一致,C++11的列表初始化只能用于初始化,不能用于已初始化对象的赋值
- 实际机制猜想:传递的实际参数为initializer_list类型,通过匹配重载函数实现调用【我不知道怎么验证这个过程,求大佬解答】
列表初始化用于函数返回值
- 在返回值类型为对象(不能是对象的引用)的函数中可以返回{}的列表初始化
- {}返回值的实际类型为initiallizer list(但不能声明为std::initializer_list),相当于返回构造函数的表达式,因此类型不能是对象的引用
引入std::initializer_list
- initializer_list为一个轻量级STL模板,声明在头文件<initializer_list>中,定义在命名空间std中
- 任意的STL容器都与未指定长度的数组有一样的初始化能力,可以填入任何数量的同类型数据,因此可以用STL容器轻易对固定类型的类进行赋值
- initializer_list是一个轻量级的模板,可以接受任意长度的同类型的数据也就是接受可变长参数,同时作为STL容器它具有STL容器的共同特征(如迭代器)
- 只有三个成员接口:begin() end() size()
- 只能被整体的初始化和赋值,迭代器遍历的数据仅可读,不能对单个数据进行修改
- 所有{}对象都是隐式创建的std::initializer_list类型字面量(右值),广泛用于实现列表初始化(不需要头文件)
代码验证
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
|
以下为运行截图

列表初始化测试
添加initializer_list为参数的构造函数后
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
以下为运行截图

添加init_list后测试截图
由此可见所有列表初始化都调用了含有initializer_list为参数的构造函数,证实了列表初始化是基于隐式转换并以initializer_list为底层实现的构想
应用
- 在声明时直接初始化堆上分配的对象(数组)
- 类:可以显式指定使用的构造函数(默认会执行无参数的构造函数)
- 内置类型:可以在分配时直接指定值
- 在函数返回对象时避免自动存储期对象销毁的问题
- 手动调用std::initializer_list实现可变参数初始化
列表初始化防止类型收窄
C++11的列表初始化还有一个额外的功能就是可以防止类型收窄,也就是C++98/03中的隐式类型转换,将范围大的转换为范围小的表示,在C++98/03中类型收窄并不会编译出错,而在C++11中,使用列表初始化的类型收窄编译将会报错:
|
1 2 3 4 5 6 7 8 9 10 11 |
|
总结
列表初始化通过C++11引入的initializer_list容器实现了初始化方式的统一,可以看作一种语法糖
初始化类对象时,通过()调用构造函数的地方都可以完全等价地用{}代替={}不会生成临时对象再拷贝初始化
更多推荐



所有评论(0)