目录
1 C++11 发展历史
2 列表初始化(统一初始化)
2.1 C++98 时代的{}局限
2.2 C++11:一切对象都可以使用{}列表初始化
3 std::initializer_list
产生背景
上篇小结
1 C++11 发展历史
C++11 是 C++ 第二个主要版本,也是自 C++98 之后最重要的一次更新。在 2011‑08‑12 被 ISO 正式采纳,早期代号叫C++0x,原本预期 2010 年前完成,实际 C++03 到 C++11 间隔长达 8 年。 自此之后 C++ 保持大约每 3 年一个版本的迭代节奏:
表格
| 版本 | 发布年份 | 核心新增代表特性 |
|---|---|---|
| C++98 | 1998 | 模板、STL 容器算法、string、IO 流 |
| C++11 | 2011 | 移动语义、统一初始化、auto/decltype、lambda、constexpr、多线程、内存模型、正则、智能指针、哈希容器 unordered 系列、std::array |
| C++14 | 2014 | 读写锁、泛型 lambda |
| C++17 | 2017 | 折叠表达式、constexpr if、结构化绑定、string_view、STL 并行算法、filesystem、any/optional/variant |
| C++20 | 2020 | 协程、模块、Concept、Ranges 库 |
| C++23 | 2023 | deducing this、print 打印库、flat 关联容器、expected、mdspan |
2 列表初始化(统一初始化)
2.1 C++98 时代的{}局限
C++98 中,{}仅仅只支持数组、结构体初始化,普通类对象不能直接使用大括号初始化。
#include<iostream> using namespace std; struct Point { int _x; int _y; }; int main() { int array1[] = {1,2,3,4,5}; int array2[5] = {0}; Point p = {1,2}; // 结构体支持 return 0; }2.2 C++11:一切对象都可以使用{}列表初始化
C++11 提出统一列表初始化,目标做到:一切对象皆可使用{}初始化。
- 内置类型、自定义类对象全部支持;
- 可以省略赋值符号
=; - 底层会先用
{...}构造临时对象,编译器优化后直接构造目标对象,不会发生拷贝; - 向容器
push_back / insert传参时,{}书写匿名对象非常便捷。
#include<iostream> #include<vector> using namespace std; struct Point { int _x; int _y; }; class Date { public: Date(int year = 1, int month = 1, int day = 1) :_year(year),_month(month),_day(day) { cout << "Date(int year, int month, 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() { // C++98原有写法 int a1[] = {1, 2, 3, 4, 5}; int a2[5] = {0}; Point p = {1, 2}; // ========= C++11列表初始化 ========= int x1 = {2}; Date d1 = {2025, 1, 1}; // 构造临时对象,编译器优化直接构造d1,不调用拷贝构造 const Date& d2 = {2024,7,25}; // 引用绑定临时对象,延长生命周期 Date d3 = {2025}; Date d4 = 2025; // 可以省略 = Point p1 {1,2}; int x2 {2}; Date d6 {2024,7,25}; const Date& d7 {2024,7,25}; vector<Date> v; v.push_back(d1); v.push_back(Date(2025,1,1)); // 直接{}传入匿名对象,代码更简洁 v.push_back({2025,1,1}); return 0; }3 std::initializer_list
产生背景
有了{}初始化,但是vector<int> v = {1,2,3,4,5};这种直接用花括号初始化容器依然做不到。 我们希望可以直接传入任意数量参数完成容器构造,于是 C++11 引入std::initializer_list。
std::initializer_list<T>底层:内部保存一个数组,仅持有两个指针:begin指向数组起始,end指向数组末尾;支持迭代器遍历。 STL 所有容器都增加接收initializer_list的构造函数与赋值重载,才支持{1,2,3}直接初始化。
容器原型示意:
template<class T> class vector { public: vector(initializer_list<T> il); vector& operator=(initializer_list<T> il); // ...其他接口 };示例代码:
#include<iostream> #include<vector> #include<map> using namespace std; int main() { std::initializer_list<int> mylist = {10,20,30}; vector<int> v1({1,2,3,4,5}); vector<int> v2 = {1,2,3,4,5}; const vector<int>& v3 = {1,2,3,4,5}; // map结合pair的{}初始化 map<string,string> dict = {{"sort","排序"},{"string","字符串"}}; // initializer_list版本赋值 v1 = {10,20,30,40,50}; return 0; }重点:
initializer_list只是代理对象,不负责保存数据本体,底层数组一般分配在栈上。
小结
- C++11 目标统一初始化语法,内置类型、自定义类都可以使用
{};可以省略=。 {}会生成临时对象,编译器返回值优化 RVO 会消除拷贝。std::initializer_list是容器支持{1,2,3}初始化的底层核心,内部只有首尾两个指针。