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_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 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 double
到double
或float
,或从double
到float
,除非源是常量表达式并且转换后的实际值在可以表示 (即使不能准确表示),或者从整数类型或无作用域枚举类型到浮点类型,除非源 是一个常量表达式,转换后的实际值将适合目标类型并且将 转换回原始类型时产生原始值,或
从整数类型或无作用域枚举类型到不能代表所有的整数类型 原始类型的值,除非源是一个常量表达式,其值在整数之后 促销活动将适合目标类型。
【讨论】:
这种同时使用括号和大括号的初始化怎么样: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 中带或不带花括号的初始化差异的主要内容,如果未能解决你的问题,请参考以下文章