C++11 核心特性深度解析(一):列表初始化
一、C++11 的发展历史与定位
1.1 C++ 版本演进时间线
C++11 是 C++ 的第二个主要版本,也是自 C++98 以来最重要的更新。在它最终由 ISO 在 2011年8月12日 采纳前,人们曾使用名称 "C++0x",因为它曾被期待在 2010 年之前发布。
C++03 与 C++11 期间花了 8 年时间,这是迄今为止最长的版本间隔。从那时起,C++ 有规律地每 3 年 更新一次。
| 年份 | 版本 | 核心特性 |
|---|---|---|
| 1998 | C++98 | STL(容器与算法)、模板基础 |
| 2003 | C++03 | 主要是 Bug 修复 |
| 2011 | C++11 | auto、decltype、lambda、右值引用、智能指针、线程库 |
| 2014 | C++14 | 泛型 lambda、变量模板、constexpr 扩展 |
| 2017 | C++17 | constexpr if、结构化绑定、文件系统、并行算法 |
| 2020 | C++20 | 概念(Concepts)、协程、模块、Ranges 库 |
| 2023 | C++23 | 打印函数(print/println)、std::expected、std::mdspan |

1.2 C++11 的核心价值
C++11 引入了大量更改,标准化了既有实践,并改进了对 C++ 程序员可用的抽象。主要贡献包括:
-
语法简化:
auto、decltype、范围 for、列表初始化 -
性能提升:右值引用与移动语义、constexpr
-
现代编程范式支持:lambda、智能指针、线程与内存模型
-
标准库增强:
std::array、std::tuple、std::unordered_map、正则表达式
二、列表初始化(List Initialization)
2.1 C++98 传统的 {} 初始化
在 C++98 中,{} 初始化主要用于数组和结构体:
struct Point {
int _x;
int _y;
};
int main() {
int array1[] = {1, 2, 3, 4, 5}; // 数组初始化
int array2[5] = {0}; // 部分初始化,其余为0
Point p = {1, 2}; // 结构体初始化(POD 类型)
return 0;
}
局限性:
-
不支持自定义类对象的
{}初始化 -
不支持
vector、map等容器的{}初始化 -
初始化方式不统一,有
()、=、{}多种形式
2.2 C++11 统一列表初始化
C++11 的目标是:一切对象皆可用 {} 初始化,这种初始化方式也称为列表初始化。
核心特性
| 特性 | 说明 |
|---|---|
| 内置类型支持 | int x1 = {2}; 或 int x2{2}; |
| 自定义类型支持 | Date d1 = {2025, 1, 1}; |
可省略 = |
Point p1{1, 2}; 等价于 Point p1 = {1, 2}; |
| 类型转换 | 本质是构造临时对象 + 拷贝构造,编译器优化为直接构造 |
| 容器便利 | v.push_back({2025, 1, 1}); 比匿名对象更简洁 |
#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, _month, _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};
int x2{2}; // 省略 =
// C++11 支持的 —— 自定义类型
// 本质:用 {2025,1,1} 构造临时对象,再拷贝构造 d1
// 编译器优化后:合二为一,直接构造 d1
Date d1 = {2025, 1, 1};
// d2 引用 {2024,7,25} 构造的临时对象
const Date& d2 = {2024, 7, 25};
// 省略 = 的写法
Point p1{1, 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;
}


重要说明
单参数类型转换:C++98 就支持单参数的类型转换,
Date d3 = {2025};和Date d4 = 2025;等价不能省略
=的情况:只有{}初始化才能省略=,Date d8 2025;是非法的编译器优化:
Date d1 = {2025, 1, 1};理论上需要"构造临时对象 + 拷贝构造",但现代编译器会优化为直接构造
2.3 std::initializer_list
initializer_list - C++ Reference
2.3.1 问题引入

虽然 {} 初始化很方便,但对象容器的初始化仍然不够灵活。比如:
vector<int> v1 = {1, 2, 3};
vector<int> v2 = {1, 2, 3, 4, 5};

如果不用 std::initializer_list,容器需要实现无数个构造函数才能支持任意多个值的初始化。
2.3.2 std::initializer_list 原理

C++11 引入了 std::initializer_list 类:
auto il = {10, 20, 30}; // il 的类型是 initializer_list<int>
底层实现:
-
底层开一个数组,将数据拷贝过来
-
std::initializer_list内部有两个指针,分别指向数组的开始和结束 -
支持迭代器遍历

#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
int main() {
std::initializer_list<int> mylist;
mylist = {10, 20, 30};
cout << sizeof(mylist) << endl; // 输出 16(两个指针的大小,64位系统)
// begin 和 end 返回的值是 initializer_list 中存的两个指针
int i = 0;
cout << mylist.begin() << endl; // 数组起始地址
cout << mylist.end() << endl; // 数组结束地址
cout << &i << endl; // 与上面的地址接近,说明数组存在栈上
// 容器支持 initializer_list 构造函数
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};
// pair 的 {} 初始化和 map 的 initializer_list 构造结合
map<string, string> dict = {
{"sort", "排序"},
{"string", "字符串"}
};
// initializer_list 版本的赋值
v1 = {10, 20, 30, 40, 50};
return 0;
}
2.3.3 模拟实现 vector 的 initializer_list 构造
template<class T>
class vector {
public:
typedef T* iterator;
vector(initializer_list<T> l) {
for (auto e : l)
push_back(e);
}
vector& operator=(initializer_list<value_type> il);
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
};
2.3.4 STL 容器新增接口
// 构造函数
vector(initializer_list<value_type> il, const allocator_type& alloc = allocator_type());
list(initializer_list<value_type> il, const allocator_type& alloc = allocator_type());
map(initializer_list<value_type> il, const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
// 赋值运算符
vector& operator=(initializer_list<value_type> il);
map& operator=(initializer_list<value_type> il);更多推荐
所有评论(0)