在C ++ 11中,以下两个陈述都是合法的:
声明1. int a[8] = {};
声明2. int a[8]{};
但是,我更喜欢声明1而不是声明2,因为我认为声明1更具表现力。
C ++ 11标准是否保证两个语句在语义上等效?
答案 0 :(得分:19)
从语义上讲,它们不一样,就像复制/直接初始化一样:
1列表初始化是从braced-init-list初始化对象或引用。这样的初始化程序是 称为初始化列表,列表中逗号分隔的初始化子句称为元素 初始化列表。初始化列表可以为空。 列表初始化可以在直接初始化或copyinitialization中进行 上下文;直接初始化上下文中的列表初始化称为直接列表初始化和 复制初始化上下文中的列表初始化称为复制列表初始化。 [...](强调我的)
原始答案,处理比较表现: 不,该标准规定了对算法的一些复杂性限制,但在这些问题上没有性能。这最好留给编译器,但所有编译器都可能生成相同的代码。
考虑复制初始化与直接初始化。标准只规定它们是什么,它从不说一个必须比另一个快,或者它们必须表现相同。这完全取决于编译器。
这是一件好事,因为编译器知道什么是最适合该平台的。如果标准确实施加了这样的限制,可能会说+
必须比{{1}更快这非常直观。但是考虑一个为乘法而构建的平台,在机器代码中计算*
的速度实际上更快。编译器必须不遗余力地将*
转换为较慢的指令,只是为了符合标准。
答案 1 :(得分:3)
标准只定义了所谓的“可观察行为”,它是I / O库调用的序列以及易失性数据的读写。没有速度要求。
你无法确定实际上哪个更快。体面编译器应该发出相同的代码,但有时编译器中存在错误,这可能会影响代码发射。
答案 2 :(得分:3)
是的,它们在语义上是等价的。
聚合(8.5.1,例如数组)上的列表初始化(8.5.4)执行聚合初始化(8.5.4p3b1)。聚合初始化无关心语法形式是直接初始化还是复制初始化;在任何一种情况下,聚合初始化的规则都适用。特别是,聚合的成员始终从初始化列表的相应子句中进行复制初始化。
有一个例外,几乎但不完全适用于您的情况;如果没有足够的元素来初始化聚合的所有成员,则标准不清楚如何初始化其余成员;它们是从{}
(空列表初始值设定项)进行列表初始化的,但未指定它们是复制列表初始化还是直接列表初始化,或者这是否取决于原始列表初始化(请参阅评论);实际上,clang和gcc在这个角落的情况下他们的行为有所不同。但是,这在您的情况下是无关紧要的,因为聚合成员类型是int
,而对于非类型类型,list {initial from {}
调用值初始化即零初始化,这是直接的,无论语法如何表单(即int i{};
和int i = {};
在语义上相同)。
有几个理由喜欢=
(复制初始化)语法:首先,它是几乎所有示例中标准使用的形式(例外是8.5.4p3中的最后两个示例,其中一个演示了缩小转换的错误,另一个演示了从空初始化列表初始化的初始化。而且,正如你所说,它更具表现力;我还发现,在列表初始化聚合时,复制初始化语法更好地反映了聚合元素本身是复制初始化的事实。
最后,在一种情况下,不需要=
的语法是必需的:其中对象是具有explicit
构造函数的非聚合类类型。因此,应该为该情况保留直接列表初始化语法。
答案 3 :(得分:0)
C ++ 11标准甚至不保证int a[8] = {};
与int aVeryLongName[8] = {};
一样快。