Ole*_*siy 349 c++ syntax initialization c++11 list-initialization
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Run Code Online (Sandbox Code Playgroud)
为什么?
我在SO上找不到答案,所以让我回答一下我自己的问题.
Ole*_*siy 311
基本上是从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)
}
Run Code Online (Sandbox Code Playgroud)
=优先于{} 的唯一情况是使用auto关键字来获取初始化程序确定的类型.
例:
auto z1 {99}; // z1 is an int
auto z2 = {99}; // z2 is std::initializer_list<int>
auto z3 = 99; // z3 is an int
Run Code Online (Sandbox Code Playgroud)
除非您有充分的理由不这样做,否则首选初始化替代方案.
Mik*_*eMB 91
关于使用列表初始化的优点已经有很好的答案,但是我个人的经验法则是尽可能不使用花括号,而是依赖于概念含义:
根据我的经验,这个规则集可以更持续高于默认情况下使用大括号,但有明确记住所有的例外,当他们不能使用或具有比括号中的"正常"的函数调用语法不同的含义应用(调用不同的重载).
例如,它非常适合标准库类型,例如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
Run Code Online (Sandbox Code Playgroud)
Red*_*III 86
有两种使用大括号初始化的原因有很多,但你应该知道,在initializer_list<>构造函数优先于其他构造,唯一的例外是默认的构造函数.这会导致构造函数和模板出现问题,其中类型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!!!
}
Run Code Online (Sandbox Code Playgroud)
假设您没有遇到此类,则没有理由不使用初始化列表.
cod*_*ing 11
更新 (2022-02-11):\n请注意,与最初发布的观点相比,最近有更多关于该主题的观点(如下),这些观点反对 {} 初始化程序的偏好,例如 Arthur Dwyer 在他关于 The 的博客文章中C++ 初始化的噩梦。
\n原答案:
\n阅读Herb Sutter 的(更新)GotW #1。\n这详细解释了这些选项和其他一些选项之间的区别,以及与区分不同选项的行为相关的几个陷阱。
\n要点/复制自第 4 节:
\n\n\n什么时候应该使用 ( ) 与 { } 语法来初始化对象?为什么?\n这里\xe2\x80\x99s 是简单的指导原则:
\n指导原则:优先使用 { } 进行初始化,例如 vector\nv = { 1, 2, 3, 4 }; 或 auto v = vector{ 1, 2, 3, 4 };,因为 \nit\xe2\x80\x99 更一致、更正确,并且完全避免了了解旧式陷阱。在单参数情况下,\n您希望只看到 = 符号,例如 int i = 42; 并且 auto x = everything;\ 省略大括号就可以了。\xe2\x80\xa6
\n这涵盖了绝大多数情况。只有一个主要\n例外:
\n\xe2\x80\xa6 极少数情况下,例如向量 v(10,20);或 auto v =\nvector(10,20);,使用带 ( ) 的初始化来显式调用\n构造函数,否则该构造函数将被initializer_list\n构造函数隐藏。
\n然而,这通常应该是 \xe2\x80\x9crare\xe2\x80\x9d 的原因是因为默认\n和复制构造已经很特殊并且可以与 { } 一起正常工作,并且\n良好的类设计现在大多避免诉诸-由于最终设计准则,用户定义的构造函数\n为 ( ) 情况:
\n指南:当您设计一个类时,避免提供一个使用initializer_list 构造函数进行重载的构造函数,这样用户就不需要使用 ( ) 来访问这样的隐藏构造函数。
\n
另请参阅有关该主题的核心指南:ES.23:首选 {}-初始化语法。
\n小智 6
只要你不使用-Wno-narrowing像谷歌在 Chromium 中所做的那样构建,它就会更安全。如果你这样做,那就不太安全了。如果没有该标志,唯一的不安全情况将由 C++20 修复。
笔记:
这两个组合意味着如果里面是原始常量,它们会更安全,但如果它们是对象,则不太安全(尽管在 C++20 中已修复)