我试图了解这个简单的C ++ 11程序输出中gcc与clang所暴露的不同行为是否是由于clang(Xcode 5.0.2,OS X 10.8.5)中的错误引起的。代码如下:
#include <iostream>
int main() {
int matrix[][3]{{1,2,3}, {4,5,6}, {7,8,9}};
auto dyn_matrix = new int[3][3]{{1,2,3}, {4,5,6}, {7,8,9}};
std::cout << matrix[0][1] << std::endl;
std::cout << dyn_matrix[0][1] << std::endl;
return 0;
}
如图所示,我正在尝试使用统一初始化来初始化大小为3x3
的匿名(resp。命名)多维数组。当使用MacPorts的gcc 4.7进行编译时,可以获得预期的输出:
$g++-mp-4.7 -std=c++11 dyn_matrix.cpp -o dyn_matrix
$ ./dyn_matrix
2
2
$
相反,如果使用clang,则输出显示为:
$ clang++ -std=c++11 -stdlib=libc++ dyn_matrix.cpp -o dyn_matrix_clang
$ ./dyn_matrix_clang
2
4
$
在这种情况下,结果(显然)是错误的。 clang --version
报告:
Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
谁应该受到责备?我,gcc还是clang?
更新2013年12月11日:该错误应该已在r196995中修复。不幸的是,我们仍然不知道Apple更新Xcode附带的clang版本需要多长时间。
更新2013年12月9日:我提交了有关LLVM bugzilla平台的错误报告。它确实被认为是一个错误,目前正在审核补丁,请参阅http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131209/095099.html。
感谢。
答案 0 :(得分:20)
更新:感谢Faisal Vali和Richard Smith,这个错误已在Clang ToT中得到纠正;请参阅提交引入的test file。
根据§8.5.1[dcl.init.aggr] ,看来Clang错了:
11 /大括号可以在初始化列表中省略,如下所示。如果 initializer-list 以左括号开头,则后续的以逗号分隔的 initializer-clauses 列表初始化子集合的成员;有没有比成员更多的初始化程序条款是错误的。但是,如果子集合的初始化列表不以左括号开头,那么列表中只有足够的 initializer-clauses 来初始化成员子聚集;剩余的 initializer-clause 用于初始化当前子聚合为成员的聚合的下一个成员。 [示例:
float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, };
是一个完全支撑的初始化:1,3和5初始化数组
y[0]
的第一行,即y[0][0]
,y[0][1]
和y[0][2]
。同样,接下来的两行初始化y[1]
和y[2]
。初始化程序提前结束,因此初始化y[3]
个元素,就像使用float()
形式的表达式显式初始化一样,即使用0.0
进行初始化。在以下示例中, initializer-list 中的大括号被省略;但初始化列表与上例中完全支撑的初始化列表具有相同的效果,float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
y的初始化程序以左括号开头,但
y[0]
的初始化程序没有,因此使用列表中的三个元素。同样,接下来的三个是y[1]
和y[2]
连续拍摄的。 - 结束示例]
我认为适用于§5.3.4[expr.new] :
15 / A new-expression 创建一个T类型的对象,按如下方式初始化该对象:
- 如果省略 new-initializer ,则默认初始化对象(§8.5);如果没有执行初始化,则该对象具有不确定的值。
- 否则, new-initializer 将根据§8.5的初始化规则进行解释,以便直接初始化。