C++中使用或不使用大括号的初始化差异

Initialization difference with or without curly braces in C++

本文关键字:初始化 C++      更新时间:2023-10-16

我们可以在C++中用两种方式初始化变量

一个:

int abc = 7;

两个:

int abc {7};

这两种方法有什么区别?编译器对待它们的方式不同吗,或者代码的执行方式不同吗?

短版本

通过{..}的初始化是列表初始化,它禁止缩小转换范围。例如,如果LLONG_MAXlong 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 doubledoublefloat,或从doublefloat,除非源是常数表达式,并且转换后的实际值在可以表示的值的范围内(即使不能准确表示),或

  • 从整数类型或无范围枚举类型到浮点类型,除非源是一个常量表达式,转换后的实际值将适合目标类型当转换回原始类型或时产生原始值

  • 从整数类型或无范围枚举类型到不能表示所有原始类型的值,除非源是其值在积分后的常量表达式促销活动将适合目标类型。

虽然int的现有回复是完整的,但我痛苦地发现,在某些情况下,(){}初始化之间还有其他差异。

关键字是{}是一个初始值设定项列表。

一种这样的情况是,使用char:的count副本进行std::string初始化

std::string stars(5, '*')

stars初始化为*****,但

std::string stars{5, '*'}

将被读取为CCD_ 25并将星号初始化为*(前面有一个隐藏字符)。

第一个是复制初始化,第二个是列表初始化。

但是,通常较少使用复制初始化。因为,如果你通过传递用户定义类型的对象来实现,它只会导致bitcopy&因此,如果用户定义的类使用指针,则可能不会产生预期的结果。