C++11 列表初始化

C++11 列表初始化

C++11 让花括号 {} 不再只是数组初始化工具,而是变成了一种更统一的初始化方式。它通常被叫做列表初始化,也有人直接叫它花括号初始化

1. 为什么它很常用?

C++11 之前,不同对象的初始化写法比较分散:

1
2
3
4
int a = 10;
int arr[3] = {1, 2, 3};
std::vector<int> v;
v.push_back(1);

有了列表初始化以后,很多对象都能统一用花括号写:

1
2
3
int a{10};
int arr[]{1, 2, 3};
std::vector<int> v{1, 2, 3};

这种写法的直接好处就是更统一,也更直观。

2. 基本用法

2.1 基本类型

1
2
3
int a{10};
double b{3.14};
char c{'A'};

2.2 数组和容器

1
2
int arr[]{1, 2, 3, 4};
std::vector<int> nums{1, 2, 3, 4, 5};

2.3 类对象

1
2
3
4
5
6
7
8
9
10
11
class Point
{
public:
Point(int x, int y) : x_(x), y_(y) {}

private:
int x_;
int y_;
};

Point p{10, 20};

3. 一个很重要的特性:防止窄化转换

列表初始化和传统 = 初始化相比,一个很大的区别是它会更严格地检查类型转换。

1
2
int a = 3.14;   // 可以通过,但会丢失精度
int b{3.14}; // 编译报错

这种行为通常是好事,因为它能帮你更早发现潜在问题。

4. 和 std::initializer_list 的关系

很多标准库容器都支持 initializer_list 构造,因此可以直接写:

1
2
std::vector<int> nums{1, 2, 3};
std::map<int, std::string> mp{{1, "one"}, {2, "two"}};

这也是为什么列表初始化在现代 C++ 里会这么常见。

5. 使用时要注意的点

5.1 花括号不总是和小括号完全等价

有些类同时提供了普通构造函数和 initializer_list 构造函数时,花括号会优先匹配后者。

1
2
std::vector<int> v1(3, 10); // 3 个 10
std::vector<int> v2{3, 10}; // 两个元素:3 和 10

这个区别非常常见,也很容易踩坑。

5.2 不要机械地把所有初始化都替换成 {}

虽然花括号很现代,但不是说所有场景都必须统一改成 {}
如果某个类型在括号和花括号下语义不同,还是应该选更清楚的那种写法。

总结

列表初始化是 C++11 里非常常用的一项基础特性。它让初始化语法更统一,同时还能避免一些窄化转换问题。
日常写代码时,基本类型、容器、类对象都很适合用它,但像 vector(3, 10)vector{3, 10} 这种语义差异,还是要特别留意。