列表初始化 - C++14中有什么变化?

9

enter image description here这两行来自cppreference

这两个语句有什么区别吗?我没有看出任何区别。

c++14之前

如果大括号初始化列表为空且T是一个带有默认构造函数的类类型,则进行值初始化。否则,如果T是一个聚合类型,则执行聚合初始化。

c++14之后

如果T是一个聚合类型,则执行聚合初始化。否则,如果大括号初始化列表为空且T是一个带有默认构造函数的类类型,则进行值初始化。


感谢@cigien@StoryTeller的编辑。 - pvc
2个回答

3

两者之间的区别在于当满足以下两个条件时会发生什么:如果T是一个聚合类(而不是数组),它肯定有一个默认构造函数,并且 花括号初始化列表为空。当然,要理解这为什么重要,我们还必须区分从空列表进行的值初始化、聚合初始化和默认初始化。

值初始化将对象零初始化,然后默认初始化它,对于聚合体来说,这意味着默认初始化了每个成员,因此值初始化是逐成员进行的(加上填充零)。聚合初始化使用{}初始化每个成员,对于许多类型而言,这又是值初始化,但对于具有用户提供的默认构造函数的类类型成员,则是默认初始化。这种区别可以在下面看到:

struct A {A() {} int i;};
struct B {A a;};  // aggregate
B b{};     // i is 0 in C++11, uninitialized in C++14
B b2=B();  // i is 0 in both versions

在仅支持 C++14 版本中,聚合体可以具有默认成员初始化程序;这当然不能对两个语言版本之间的行为差异做出贡献,但它在这两个规则之间的行为也没有区别(因为它仅替换了通用默认初始化)。

并非所有的聚合体都有一个未删除的默认构造函数(例如,struct X {const int x; };)。 - T.C.
@T.C.:没错,但这里没有考虑构造函数是否被删除的情况(当然,初始化可能是不合法的)。你的意思是,在C++11中使用“{}”初始化此类类型是不合法的,而在C++14中则不是吗? - Davis Herring
在N3337中,格式良好性取决于X的已删除默认构造函数是否是平凡的 - 我认为根据当时的定义它是平凡的。如果我正确地阅读了维基笔记,CWG1301更改了值初始化的定义以拒绝已删除的构造函数,并重新排序了项目符号以保持{}的有效性。 - T.C.

0

区别在于检查的顺序,因此聚合类型检查首先进行,然后才是其余部分。


3
这个改变会产生什么影响? - Evg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接