用列表初始化代替用等号或小括号的方式进行初始化
6.6.1 ID_missingBracedSyntax
等号或小括号初始化不检查类型转换是否安全,列表初始化会进行相关检查,可避免数据丢失等问题,提高了安全性,而且列表初始化在语法形式上更统一,有助于提高可读性。
示例:
void foo(double x) {
float a = x; // Non-compliant, may loss data
float b(x); // Non-compliant, may loss data
float c{x}; // Compliant, list-initialization, compile-time protected
float d{static_cast<float>(x)}; // Compliant, intentional conversion
....
}
例中 a 和 b 的初始化可能存在数据丢失等问题,c 的初始化无法通过编译,使问题得以及时修正,d 为有意转换,可以通过编译。
在大多数情况下,列表出初始化均可代替等号或小括号初始化,如初始赋值、调用构造函数等:
struct A {
int x{1}; // ‘x’ is set to 1
A() = default; // Default constructor
A(int i): x{i} // Overloaded constructor
{}
};
A a{}; // Calls the default constructor
A b{1}; // Calls the overloaded constructor
A c{a}; // Copy-initialization
A d[]{1, 2}; // Initializate an array
struct B {
int i, j;
};
B e{}; // Zero-initialization, members are set to 0
B f{1, 2}; // Members are set to 1 and 2 respectively
相比于列表初始化,小括号初始化的语法不统一:
B g(); // This is a function, not an object
B h = B(); // Zero-initialization, verbose
注意,例中 B g(); 是函数声明,易与对象定义混淆,改用 B g{}; 可以简练有效的对成员进行零初始化。
列表初始化的大括号及之间的内容称为“初始化列表”,初始化列表之前可以有一个等号,但 = {....} 是拷贝初始化,不带等号才是直接初始化,虽然复制成本可被优化,但仍应避免使用多余的符号。
struct C {
int x;
explicit C(int i): x{i} {}
};
C a{1}; // OK
C b = {1}; // Compile error
构造函数被 explicit 关键字限定,故无法进行拷贝初始化。
例外:
std::vector<int> v(5, 0); // 5 elements with value 0
std::vector<int> w{5, 0}; // 2 elements, first is 5, second is 0
初始化列表的类型为 std::initializer_list,如果相关构造函数对其有重载,则调用重载了的构造函数。std::vector 对 initializer_list 进行了重载,可以像初始化数组一样初始化 vector,例中 v 有 5 个元素,每个元素都是 0,而 w 有两个元素,第一个是 5,第二个是 0,这一点列表初始化无法代替用括号的方式进行初始化。
相关
依据
ISO/IEC 14882:2011 8.5.4