【C++11】列表初始化initializer_list深度剖析 一、C的发展史C11 是 C 的第二个主要版本并且是从 C98 起的最重要更新。它引入了大量更改标准化了既有实践并改进了对C程序员可用的抽象。在它最终由 ISO 在 2011 年 8月12日采纳前人们曾使⽤名称“C0x”因为它曾被期待在 2010 年之前发布。C03 与 C11 期间花了 8 年时间故而这是迄今为止最长的版本间隔。从那时起C 有规律地每 3 年更新一次。二、列表初始化1. 出现的问题在C98中我们可以用{}初始化数组和结构体。int arr[] {1,2,3}; struct Point { int x; int y; }; Point p {1,2};但是我们不能这样初始化类对象string s {hello}; // C98不支持2. C11的列表初始化为了解决C98中列表初始化的问题C11的列表初始化应运而生它可以应用于任何数据类型的初始化实现了初始化方式的统一。这个初始化内置类型支持自定义类型也支持自定义类型本质是类型转换中间会产生临时对象最后优化了以后变成直接构造。{}初始化的过程中可以省略掉C11列表初始化的本意是想实现一个大统一的初始化方式其次他在有些场景下带来的不少便利如容器push/insert多参数构造的对象时{}初始化会很方便2.1 内置类型的初始化int a2; int b{2};列表初始化与普通的初始化完全一样我们可以看看它们底层的汇编语言可见它们没的汇编语言一模一样没有任何区别。2.2 自定义类型的初始化class Date { public: Date(const int year,const int month,const int day) :_year(year),_month(month),_day(day) { cout Date(const int year,const int month,const int day)endl; } Date(const Date d) :_year(d._year), _month(d._month), _day(d._day) { cout Date(const Date d) endl; } private: int _year; int _month; int _day; }; int main() { Date d1(2026, 6, 22); Date d2 { 2026,6,22 }; return 0; }自定义类型也是一样的列表初始化与普通初始化没有区别如果在编译器不优化的情况下对于Date d2 { 2026,6,22 };编译器会先先生成一个{2026,6,22}的临时变量再拷贝给d2。编译器采取了优化它会直接构造{2026,6,22}的对象d1。我们可以运行以上代码验证只有两个构造没有拷贝印证了之前的结论。const Date d2 { 2026, 6, 22 };对于d2它引用的是{2026,6,22}产生的临时对象临时对象具有常性是一个右值必须要加const至于右值的概念下一节会详细讲述。对于类型转换C98支持单参数类型转换可以省去{}//在构造函数后两个参数为缺省值的情况下 Date d3 { 2026 }; //C11列表初始化 Date d4 2026; //C98单参数对于列表初始化来讲可以省略“”但是C98的单参数类型转换不能省略“”。Date d3{ 2026 }; //C11可行 Date d4 2026; //C98不支持2.3 STL中的应用我们就以vector的push_back为例vectorDate v; v.push_back(Date{ 2026,6,22 }); v.push_back({ 2026,6,22 });我们在一个vector Date 中插入数据如果不使用初始化列表的话我们是创建一个匿名对象再进行插入那么现在我们可以直接省略Date直接插入{}。三、std::initializer_list1. 什么是initializer_list我们先看一行代码Date d2 { 2026,6,22 }; vectorint v1{ 1,2,3,4,5 };这两个看上去好像是同一种语法但是它们在底层调用上有所区别。对于Date来讲编译器看到{ 2026,6,22 }它会匹配到Date(int,int,int)的构造函数直接构造。对于vector来讲编译器看到{1,2,3,4,5}它会匹配到vector(initializer_list)引入正题initializer_list就是C11 提供的一个轻量级容器之前我们也有提到过。我们先来看看它的声明它的接口也是非常的精简2. 底层与迭代器它的底层结构大概是这样templateclass T class initializer_list { public: typedef const T* iterator; typedef const T* const_iterator; iterator begin() const { return _first; } iterator end() const { return _last; } size_t size() const { return _last - _first; } private: const T* _First; const T* _Last; };它实际上就是_First和_Last两个指针两指针分别指向数据头和尾的下一个它的本质就是一个只读区间。它里面有begin和end两个迭代器因此它支持范围for。它的内层是开辟在栈区的。3. vector的情形当我们调用vectorint v1{ 1,2,3,4,5 };编译器匹配vector(initializer_list)实际情况下编译器直接将列表里的数给v1而不产生额外的开销。4. 总结项目底层实现存储结构两个指针begin()const T*end()const T*iteratorconst T*支持范围for支持元素可修改不支持本质一个只读区间要注意initializer_list本身不存储数据只是对编译器生成的临时数组进行包装。它内部仅维护[first,last)两个指针其迭代器本质就是const T*。