列表初始化

成员变量初始化方式分析

uint32_t mWidth {0};uint32_t mWidth = 0;

uint32_t mWidth {0}; 这种初始化方式是可以的,它使用了 C++11 引入的统一初始化语法(也称为列表初始化),和传统的 uint32_t mWidth = 0; 初始化方式各有特点,下面为你详细分析:

语法解释

  • **uint32_t mWidth = 0;**:这是 C++ 从 C 语言继承而来的传统初始化方式,称为拷贝初始化(copy initialization)。它会先创建一个临时对象,然后将这个临时对象的值拷贝给要初始化的变量。对于像 uint32_t 这种基本数据类型,编译器通常会进行优化,直接将值赋给变量,不会有额外的性能开销。
  • **uint32_t mWidth {0};**:这是 C++11 引入的统一初始化语法,也叫列表初始化(list initialization)或大括号初始化(brace initialization)。使用这种方式初始化时,变量会直接被初始化为大括号内的值,避免了一些潜在的窄化转换问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <cstdint>
#include <iostream>

class MyClass {
public:
// 使用列表初始化
uint32_t mWidth {0};
// 使用传统的拷贝初始化
uint32_t mHeight = 0;
};

int main() {
MyClass obj;
std::cout << "Width: " << obj.mWidth << std::endl;
std::cout << "Height: " << obj.mHeight << std::endl;
return 0;
}

两者区别和使用场景

1. 防止窄化转换

列表初始化会阻止可能导致数据丢失的窄化转换,而传统的拷贝初始化则不会。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <cstdint>
#include <iostream>

int main() {
// 传统初始化,允许窄化转换
uint32_t num1 = 3.14;
std::cout << "num1: " << num1 << std::endl;

// 列表初始化,不允许窄化转换,编译报错
// uint32_t num2 {3.14};

return 0;
}

在上述代码中,uint32_t num1 = 3.14; 会将 3.14 截断为 3 进行赋值;而 uint32_t num2 {3.14}; 会在编译时产生错误,因为这是一个窄化转换。

2. 语法一致性

列表初始化提供了一种统一的初始化语法,无论是基本数据类型、数组、结构体还是类对象,都可以使用相同的语法进行初始化。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <cstdint>
#include <vector>

int main() {
// 基本数据类型
uint32_t num {10};

// 数组
int arr[3] {1, 2, 3};

// 标准容器
std::vector<int> vec {4, 5, 6};

return 0;
}

3. 兼容性和习惯

传统的拷贝初始化在 C++ 早期就已经存在,在旧代码中更为常见;而列表初始化是 C++11 引入的新特性,如果你使用的是支持 C++11 及以上标准的编译器,并且希望代码更加安全和统一,推荐使用列表初始化。

综上所述,uint32_t mWidth {0}; 是一种合法且有优势的初始化方式,你可以根据具体的需求和场景选择合适的初始化方法。