[英]What are the advantages of list initialization (using curly braces)?
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Why?为什么?
Basically copying and pasting from Bjarne Stroustrup's "The C++ Programming Language 4th Edition" :基本上是从 Bjarne Stroustrup 的“The C++ Programming Language 4th Edition”复制和粘贴:
List initialization does not allow narrowing (§iso.8.5.4).列表初始化不允许缩小 (§iso.8.5.4)。 That is:
那是:
Example:例子:
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)
}
The only situation where = is preferred over {} is when using auto
keyword to get the type determined by the initializer. = 优于 {} 的唯一情况是使用
auto
关键字来获取由初始化程序确定的类型。
Example:例子:
auto z1 {99}; // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int
Prefer {} initialization over alternatives unless you have a strong reason not to.除非您有充分的理由不这样做,否则首选 {} 初始化而不是替代方法。
There are already great answers about the advantages of using list initialization, however my personal rule of thumb is NOT to use curly braces whenever possible, but instead make it dependent on the conceptual meaning:关于使用列表初始化的优点已经有了很好的答案,但是我个人的经验法则是尽可能不要使用花括号,而是让它依赖于概念含义:
In my experience, this ruleset can be applied much more consistently than using curly braces by default, but having to explicitly remember all the exceptions when they can't be used or have a different meaning than the "normal" function-call syntax with parenthesis (calls a different overload).根据我的经验,这个规则集可以比默认使用花括号更一致地应用,但是当它们不能被使用或具有与带括号的“正常”函数调用语法不同的含义时,必须明确记住所有异常(调用不同的重载)。
It eg fits nicely with standard library-types like std::vector
:例如,它非常适合标准库类型,例如
std::vector
:
vector<int> a{10, 20}; //Curly braces -> fills the vector with the arguments
vector<int> b(10, 20); //Parentheses -> 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
There are MANY reasons to use brace initialization, but you should be aware that the initializer_list<>
constructor is preferred to the other constructors , the exception being the default-constructor.使用大括号初始化有很多原因,但您应该知道
initializer_list<>
构造函数优于其他构造函数,默认构造函数是例外。 This leads to problems with constructors and templates where the type T
constructor can be either an initializer list or a plain old ctor.这会导致构造函数和模板出现问题,其中类型
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!!!
}
Assuming you don't encounter such classes there is little reason not to use the intializer list.假设您没有遇到此类类,则没有理由不使用初始化器列表。
It only safer as long as you don't build with -Wno-narrowing like say Google does in Chromium.只要您不使用 -Wno-narrowing 进行构建,就像 Google 在 Chromium 中所做的那样,它只会更安全。 If you do, then it is LESS safe.
如果你这样做了,那就不太安全了。 Without that flag the only unsafe cases will be fixed by C++20 though.
如果没有这个标志,唯一的不安全情况将由 C++20 修复。
Note: A) Curly brackets are safer because they don't allow narrowing.注意:A)大括号更安全,因为它们不允许变窄。 B) Curly brackers are less safe because they can bypass private or deleted constructors, and call explicit marked constructors implicitly.
B)花括号不太安全,因为它们可以绕过私有或删除的构造函数,并隐式调用显式标记的构造函数。
Those two combined means they are safer if what is inside is primitive constants, but less safe if they are objects (though fixed in C++20)这两个组合意味着如果里面是原始常量,它们会更安全,但如果它们是对象,则安全性会降低(尽管在 C++20 中已修复)
Update (2022-02-11): Note that there are more recent opinions on that subject to the one originally posted (below), which argue against the preference of the {} initializer, such as Arthur Dwyer in his blog post on The Knightmare of Initialization in C++ .更新 (2022-02-11):请注意,与最初发布的主题(下)相比,有更多关于该主题的最新意见,这些意见反对 {} 初始化程序的偏好,例如 Arthur Dwyer 在他关于The Knightmare的博客文章中C++ 中的初始化。
Original Answer:原答案:
Read Herb Sutter's (updated) GotW #1 .阅读Herb Sutter 的(更新的)GotW #1 。 This explains in detail the difference between these, and a few more options, along with several gotchas that are relevant for distinguishing the behavior of the different options.
这详细解释了这些之间的区别,以及更多选项,以及与区分不同选项的行为相关的几个陷阱。
The gist/copied from section 4:第 4 节的要点/复制:
When should you use ( ) vs. { } syntax to initialize objects?
什么时候应该使用 ( ) 与 { } 语法来初始化对象? Why?
为什么? Here's the simple guideline:
这是简单的指南:
Guideline: Prefer to use initialization with { }, such as vector v = { 1, 2, 3, 4 };
指导原则:优先使用带{}的初始化,如vector v = { 1, 2, 3, 4 }; or auto v = vector{ 1, 2, 3, 4 };, because it's more consistent, more correct, and avoids having to know about old-style pitfalls at all.
或 auto v = vector{ 1, 2, 3, 4 };,因为它更一致、更正确,并且完全避免了了解旧式陷阱。 In single-argument cases where you prefer to see only the = sign, such as int i = 42;
在您希望只看到 = 符号的单参数情况下,例如 int i = 42; and auto x = anything;
和自动 x = 任何东西; omitting the braces is fine.
省略括号很好。 …
…
That covers the vast majority of cases.
这涵盖了绝大多数情况。 There is only one main exception:
只有一个主要的例外:
… In rare cases, such as vector v(10,20);
… 在极少数情况下,例如向量 v(10,20); or auto v = vector(10,20);, use initialization with ( ) to explicitly call a constructor that is otherwise hidden by an initializer_list constructor.
或 auto v = vector(10,20);,使用 ( ) 初始化显式调用构造函数,否则该构造函数会被 initializer_list 构造函数隐藏。
However, the reason this should be generally “rare” is because default and copy construction are already special and work fine with { }, and good class design now mostly avoids the resort-to-( ) case for user-defined constructors because of this final design guideline:
然而,这通常应该是“罕见的”的原因是因为默认和复制构造已经很特殊并且可以与 { } 一起工作,并且好的类设计现在大多避免用户定义构造函数的求助于()情况,因为这个最终设计指南:
Guideline: When you design a class, avoid providing a constructor that ambiguously overloads with an initializer_list constructor, so that users won't need to use ( ) to reach such a hidden constructor.
指南:当你设计一个类时,避免提供一个用 initializer_list 构造函数重载的构造函数,这样用户就不需要使用 () 来访问这样一个隐藏的构造函数。
Also see the Core Guidelines on that subject: ES.23: Prefer the {}-initializer syntax .另请参阅有关该主题的核心指南: ES.23: Prefer the {}-initializer syntax 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.