C++中使用或不使用大括号的初始化差异
Initialization difference with or without curly braces in C++
我们可以在C++中用两种方式初始化变量
一个:
int abc = 7;
两个:
int abc {7};
这两种方法有什么区别?编译器对待它们的方式不同吗,或者代码的执行方式不同吗?
短版本
通过{..}
的初始化是列表初始化,它禁止缩小转换范围。例如,如果LLONG_MAX
是long long int
的最大值,而您的int
不能表示:
int x = LLONG_MAX; // probably accepted with a warning
int x {LLONG_MAX}; // error
类似:
long long y = /*something*/;
int x = y; // accepted, maybe with a warning
int x {y}; // error
长版本
表单的初始化
T x = a;
是复制初始化;任一形式的初始化
T x(a);
T x{a};
是直接初始化,[dcl.init]/15-16。
[dcl.init]/14然后说:
初始化的形式(使用括号或
=
)通常是无关紧要的,但当初始化器或正在初始化的实体具有类类型时,它确实很重要;请参见下文。
因此,对于非类类型,初始化的形式并不重要。然而,这两种直接初始化之间存在差异:
T x(a); // 1
T x{a}; // 2
类似地,在这两个副本初始化之间:
T x = a; // 1
T x = {a}; // 2
即,具有{..}
的那些使用列表初始化。{..}
被称为支持的初始化列表。
因此,当您比较T x = a;
和T x {a};
时,有两个区别:复制与直接初始化,以及"非列表"与列表初始化。正如其他人已经提到的,在上面的引用中,对于非类类型T
,复制和直接init之间没有区别。但是,listinit和no-listinit之间是有区别的。也就是说,我们还可以比较
int x (a);
int x {a};
在这种情况下,列表初始化禁止缩小转换范围。缩小转换在[dcl.init.list]/7中定义为:
缩小转换是一种隐式转换
从浮点类型到整数类型,或
从
long double
到double
或float
,或从double
到float
,除非源是常数表达式,并且转换后的实际值在可以表示的值的范围内(即使不能准确表示),或从整数类型或无范围枚举类型到浮点类型,除非源是一个常量表达式,转换后的实际值将适合目标类型当转换回原始类型或时产生原始值
从整数类型或无范围枚举类型到不能表示所有原始类型的值,除非源是其值在积分后的常量表达式促销活动将适合目标类型。
虽然int
的现有回复是完整的,但我痛苦地发现,在某些情况下,()
和{}
初始化之间还有其他差异。
关键字是{}
是一个初始值设定项列表。
一种这样的情况是,使用char
:的count
副本进行std::string
初始化
std::string stars(5, '*')
将stars
初始化为*****
,但
std::string stars{5, '*'}
将被读取为CCD_ 25并将星号初始化为*
(前面有一个隐藏字符)。
第一个是复制初始化,第二个是列表初始化。
但是,通常较少使用复制初始化。因为,如果你通过传递用户定义类型的对象来实现,它只会导致bitcopy&因此,如果用户定义的类使用指针,则可能不会产生预期的结果。
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- C++成员初始化
- 为什么在C++中首先初始化成员类
- 同时具有"聚合初始化"和"模板推导"
- 初始化具有非默认构造函数的std::数组项的更好方法
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 在C和C++中初始化结构中的数组
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 在函数内部的声明中初始化数组,并在外部使用它
- 继承:构造函数,初始化C++11中基类的类C数组成员