C++11 中带或不带花括号的初始化差异

Posted

技术标签:

【中文标题】C++11 中带或不带花括号的初始化差异【英文标题】:Initialization difference with or without Curly braces in C++11 【发布时间】:2014-02-04 16:02:30 【问题描述】:

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

一个:

int abc = 7;

两个:

int abc 7;

这两种方法有什么区别?

编译器如何区别对待它们或执行这些代码的方式?

【问题讨论】:

en.cppreference.com/w/cpp/language/initialization 对于int,唯一的区别是禁止缩小转换,例如来自太大而无法放入int 的文字。对于类类型,它可能会变得复杂,具体取决于您想了解差异的详细程度。 【参考方案1】:

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

关键字是是一个初始化列表。

这样一种情况是,std::string 初始化与 count char 的副本:

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

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

std::string stars5, '*'

将被读取为std::string stars(char(5), '*'),并将星号初始化为*(前面有一个隐藏字符)。

【讨论】:

【参考方案2】:

短版

通过.. 初始化是列表初始化,它禁止缩小转换。例如,如果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 xa;

直接初始化,[dcl.init]/15-16。

[dcl.init]/14 然后说:

初始化的形式(使用括号或=)通常是无关紧要的,但是当初始化器或被初始化的实体具有类类型时就很重要;见下文。

所以对于非类类型,初始化的形式 无关紧要。但是,这两种直接初始化是有区别的:

T x(a);  // 1
T xa;  // 2

同样,在这两个复制初始化之间:

T x = a;    // 1
T x = a;  // 2

.. 使用列表初始化。 .. 被称为 braced-init-list

因此,当您比较 T x = a;T x a; 时,有 两个 区别:复制与直接初始化,以及“非列表”与列表初始化。正如其他人在上面的引用中已经提到的那样,对于非类类型T,复制初始化和直接初始化没有区别。但是,list-init 和没有 list-init 之间是有区别的。也就是说,我们也可以比较

int x (a);
int x a;

在这种情况下,列表初始化禁止缩小转换。在 [dcl.init.list]/7 中将缩小转换定义为:

窄化转换是隐式转换

从浮点类型到整数类型,或者

long doubledoublefloat,或从doublefloat,除非源是常量表达式并且转换后的实际值在可以表示 (即使不能准确表示),或者

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

从整数类型或无作用域枚举类型到不能代表所有的整数类型 原始类型的值,除非源是一个常量表达式,其值在整数之后 促销活动将适合目标类型。

【讨论】:

这种同时使用括号和大括号的初始化怎么样:std::random_device() @moooeeeep 这不是一种单独的初始化。它使用表达式std::random_device 构造一个std::random_device 类型的临时对象,然后调用该对象的重载operator(),就像std::random_device rd; rd() 那样。 random_device 有一个 operator(),它调用 RNG 并返回一个(伪)随机数,参见 en.cppreference.com/w/cpp/numeric/random/random_device/… 很好,谢谢!既然你解释了它,它似乎很明显。 我尝试使用 int b12147483648 进行初始化; .但我没有收到错误,而是只收到警告“警告:将'2147483648ll'从'long long int'缩小到'int' inside [-Wnarrowing]|。为什么会这样? @Rajesh 哪个编译器和版本?显然,这只是在 gcc 5 之前的警告。另请参阅:gcc.gnu.org/bugzilla/show_bug.cgi?id=55783【参考方案3】:

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

但是,通常复制初始化很少使用。因为,如果您通过传递用户定义类型的对象来执行此操作,它只会导致位复制,因此如果用户定义的类使用指针,则可能不会产生预期的结果。

【讨论】:

如果他们有复制构造函数,肯定不会?我现在很困惑。 @RichieHH 如果用户定义的类型有指针,那么应该更喜欢编写复制构造函数以及构造函数和析构函数(规则 3)。但是,如果没有复制构造函数,那么它将导致“浅复制”并可能导致悬空指针。 没错。使用指针的用户定义类型应该具有复制和初始化构造函数。也许编辑您的回复。感谢您回来。

以上是关于C++11 中带或不带花括号的初始化差异的主要内容,如果未能解决你的问题,请参考以下文章

at&t 汇编语法中带 $ 或不带 $ 符号的数字有啥区别?

C++中带括号的数组对象的初始化

PostgreSQL中带/不带时区的时间戳之间的差异

使用带或不带括号的 python 装饰器

初始化数组时使用(或不使用)括号

在 ES6 中导入带或不带大括号 [重复]