MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
为什么?
我在SO上找不到答案,所以让我回答一下我自己的问题。
基本上是从Bjarne Stroustrup的“The C ++ Programming Language 4th Edition”中复制和粘贴:
列表初始化不允许缩小(§iso.8.5.4)。那是:
例:
void fun(double val, int val2) {
int x2 = val; // if val==7.9, x2 becomes 7 (bad)
char c2 = val2; // if val2==1025, c2 becomes 1 (bad)
int x3 {val}; // error: possible truncation (good)
char c3 {val2}; // error: possible narrowing (good)
char c4 {24}; // OK: 24 can be represented exactly as a char (good)
char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
// represented as a char (good)
int x4 {2.0}; // error: no double to int value conversion (good)
}
=优先于{}的唯一情况是使用auto
关键字来获取初始化程序确定的类型。
例:
auto z1 {99}; // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int
除非您有充分的理由不这样做,否则首选初始化替代方案。
使用大括号初始化有很多原因,但是你应该知道initializer_list<>
构造函数比其他构造函数更受欢迎,例外是default-constructor。这导致构造函数和模板的问题,其中类型T
构造函数可以是初始化列表或普通旧ctor。
struct Foo {
Foo() {}
Foo(std::initializer_list<Foo>) {
std::cout << "initializer list" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy ctor" << std::endl;
}
};
int main() {
Foo a;
Foo b(a); // copy ctor
Foo c{a}; // copy ctor (init. list element) + initializer list!!!
}
假设您没有遇到此类,则没有理由不使用初始化列表。
关于使用列表初始化的优点已经有很好的答案,但是我个人的经验法则是尽可能不使用花括号,而是依赖于概念含义:
根据我的经验,这个规则集可以比默认情况下使用花括号更加一致地应用,但是当它们不能被使用时必须明确地记住所有异常,或者具有与“普通”函数不同的含义 - 带括号的调用语法(调用不同的重载)。
它例如非常适合像std::vector
这样的标准库类型:
vector<int> a{10,20}; //Curly braces -> fills the vector with the arguments
vector<int> b(10,20); //Parenthesis -> uses arguments to parametrize some functionality,
vector<int> c(it1,it2); //like filling the vector with 10 integers or copying a range.
vector<int> d{}; //empty braces -> default constructs vector, which is equivalent
//to a vector that is filled with zero elements