C ++ 11是否保证“int a [8] = {};”在语义上等同于“int a [8] {};”?

时间:2013-02-14 09:01:02

标签: c++ performance c++11 initialization standards

在C ++ 11中,以下两个陈述都是合法的:

声明1. int a[8] = {};

声明2. int a[8]{};

但是,我更喜欢声明1而不是声明2,因为我认为声明1更具表现力。

C ++ 11标准是否保证两个语句在语义上等效?

4 个答案:

答案 0 :(得分:19)

从语义上讲,它们不一样,就像复制/直接初始化一样:

8.5.4列表初始化[dcl.init.list]

  

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] = {};一样快。