【C++11】列表初始化详解:统一、安全的初始化方式

发布于:2024-11-28 ⋅ 阅读:(11) ⋅ 点赞:(0)

一、概念

在C++中,列表初始化(List Initialization)是一种通过使用大括号 {} 来初始化变量的方法。它是C++11引入的特性,提供了更加统一且类型安全的初始化方式。


二、特点

  1. 统一初始化:无论是数组、对象、内置类型还是容器,列表初始化都可以用统一的语法来初始化。
  2. 防止窄化(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};     // 另一种写法

五、列表初始化的优点

  1. 统一性:无论是内置类型、数组、类、标准库容器,所有类型都可以使用列表初始化。
  2. 类型安全:防止窄化转换,例如,从 doubleint,列表初始化会发生编译错误,而传统的 = 初始化则不会(会自动进行窄化转换)。

例子:防止窄化转换

double pi = 3.14159;
int x = {pi};  // 错误:编译时错误,不能将 double 转换为 int

int y = 10;
double z = {y};  // 正确:从 int 到 double 是合法的转换

六、列表初始化的常见应用场景

  1. 防止隐式转换:传统的圆括号初始化允许发生可能丢失数据的转换,而列表初始化会阻止这种窄化转换。
  2. 数组和容器初始化:提供简洁的语法来初始化容器和数组。
  3. 结构体和类的初始化:提供统一的语法来初始化对象的成员变量。

七、列表初始化中的 “窄化”(Narrowing)问题

列表初始化禁止了窄化(Narrowing)转换,窄化转换是指将一个较大的类型(如 double)转换为较小的类型(如 int),这可能会丢失数据。为了避免这种潜在的错误,列表初始化在遇到窄化转换时会生成编译错误。

例如:

double pi = 3.14159;
int x = {pi};  // 错误:double 到 int 的窄化转换

八、其他细节

  • 默认初始化:如果没有给出初始化值,使用列表初始化的对象会被默认初始化:

    int a{};    // 默认初始化为 0
    double b{}; // 默认初始化为 0.0
    
  • 初始化的顺序:当使用列表初始化时,类成员或对象的初始化顺序与声明顺序一致。这与传统构造函数初始化列表的顺序一致。


网站公告

今日签到

点亮在社区的每一天
去签到