1. C++11列表初始化详解
1.1 统一初始化语法
C++11引入的大括号{}初始化语法,本质上是为了解决C++98中初始化方式不统一的问题。在旧标准中,数组、结构体、类等不同对象的初始化方式各异,导致代码风格混乱。新标准通过{}初始化实现了"一切对象皆可用大括号初始化"的目标。
这种语法糖带来的好处非常明显:
- 避免了"="和"()"混用导致的歧义
- 内置类型和自定义类型的初始化方式得到统一
- 防止窄化转换(编译器会对可能丢失信息的类型转换发出警告)
cpp复制// C++98风格
int arr[] = {1, 2, 3};
Point p = {1, 2};
// C++11风格
int x{5}; // 等同于int x = 5;
Date d{2024, 7, 25}; // 直接调用构造函数
注意:使用{}初始化时,编译器会优先匹配带有std::initializer_list参数的构造函数。如果没有这样的构造函数,才会考虑其他构造函数。
1.2 初始化列表的底层原理
当看到vector<int> v = {1,2,3};这样的代码时,背后实际上发生了以下步骤:
- 编译器将{1,2,3}转换为std::initializer_list对象
- vector的构造函数接收这个initializer_list
- 在堆上分配足够的内存空间
- 将initializer_list中的元素拷贝到vector中
initializer_list本质上是一个轻量级的包装器,包含两个指针:一个指向数组开头,一个指向数组末尾。这个数组通常存放在栈上,生命周期与initializer_list对象相同。
cpp复制// 手动使用initializer_list
std::initializer_list<int> il = {10, 20, 30};
for(auto it = il.begin(); it != il.end(); ++it) {
cout << *it << " ";
}
1.3 三种初始化方式对比
在实际开发中,我们会遇到三种初始化方式:
- 传统赋值式:
cpp复制vector<int> v1 = {1,2,3};
