文章目录
一、概念
在C++中,列表初始化(List Initialization)是一种通过使用大括号 {}
来初始化变量的方法。它是C++11引入的特性,提供了更加统一且类型安全的初始化方式。
二、特点
- 统一初始化:无论是数组、对象、内置类型还是容器,列表初始化都可以用统一的语法来初始化。
- 防止窄化(Narrowing)转换:与传统的初始化方式(如圆括号初始化)不同,列表初始化会阻止那些可能导致数据丢失的“窄化”转换。
三、基本语法
T var = {value}; // 列表初始化
T var{value}; // 列表初始化(另一种写法)
这里 T
是类型,value
是要初始化的值。
四、实例
1. 初始化内置类型
int a = {10}; // 使用列表初始化
int b{20}; // 另一种写法
2. 初始化数组
int arr[3] = {1, 2, 3}; // 数组初始化
int arr2[] = {1, 2, 3}; // 自动推导数组大小
3. 初始化类对象
假设有一个类 Person
:
class Person {
public:
std::string name;
int age;
// 构造函数
Person(const std::string& n, int a) : name(n), age(a) {}
};
可以使用列表初始化来初始化类的成员:
Person p1{"John", 30}; // 使用列表初始化
4. 初始化标准容器(如 std::vector
)
std::vector<int> vec = {1, 2, 3, 4}; // 初始化 vector
std::vector<int> vec2{5, 6, 7}; // 另一种写法
5. 初始化结构体
struct Point {
int x, y;
};
Point p1 = {10, 20}; // 使用列表初始化
Point p2{30, 40}; // 另一种写法
五、列表初始化的优点
- 统一性:无论是内置类型、数组、类、标准库容器,所有类型都可以使用列表初始化。
- 类型安全:防止窄化转换,例如,从
double
到int
,列表初始化会发生编译错误,而传统的=
初始化则不会(会自动进行窄化转换)。
例子:防止窄化转换
double pi = 3.14159;
int x = {pi}; // 错误:编译时错误,不能将 double 转换为 int
int y = 10;
double z = {y}; // 正确:从 int 到 double 是合法的转换
六、列表初始化的常见应用场景
- 防止隐式转换:传统的圆括号初始化允许发生可能丢失数据的转换,而列表初始化会阻止这种窄化转换。
- 数组和容器初始化:提供简洁的语法来初始化容器和数组。
- 结构体和类的初始化:提供统一的语法来初始化对象的成员变量。
七、列表初始化中的 “窄化”(Narrowing)问题
列表初始化禁止了窄化(Narrowing)转换,窄化转换是指将一个较大的类型(如 double
)转换为较小的类型(如 int
),这可能会丢失数据。为了避免这种潜在的错误,列表初始化在遇到窄化转换时会生成编译错误。
例如:
double pi = 3.14159;
int x = {pi}; // 错误:double 到 int 的窄化转换
八、其他细节
默认初始化:如果没有给出初始化值,使用列表初始化的对象会被默认初始化:
int a{}; // 默认初始化为 0 double b{}; // 默认初始化为 0.0
初始化的顺序:当使用列表初始化时,类成员或对象的初始化顺序与声明顺序一致。这与传统构造函数初始化列表的顺序一致。