该代码在Coliru中编译并带有警告[在a[1].i
中的a[2].i
表达式中的统一成员std::cout <<
和main()
],但通常在Ideone中编译。
#include <iostream>
struct A
{
int i;
A(int j) : i{j} {};
A() = default;
};
int main() {
A a[3] = { A(1) };
std::cout << a[1].i << ' ' << a[2].i << '\n';
}
根据我对iso§8.5 p7的解释,Ideon是正确的,因为该条款的第四个要点。
这是N3797的8.5 p7
最佳答案
对于具有默认默认构造函数和另一个非默认构造函数的类,C++ 11和N3797之间的值初始化行为存在明显差异。 C++ 11§8.5/7:
N3797§8.5/8:
您的struct A
具有用户声明的默认构造函数A() = default;
和用户提供的非默认构造函数A(int j) : i{j} {}
。在C++ 11中,它以第一个项目符号为准:它具有用户提供的构造函数,因此将调用默认构造函数(不执行任何操作:A
的默认构造函数很简单)。在N3797中,第二个项目符号适用,因为A
是“没有用户提供或删除的默认构造函数”,因此该对象被零初始化。
简而言之,在C++ 11中使用或用户提供的任何构造函数的类的对象的值初始化在默认初始化之前不会执行零初始化。在N3797中,没有用户提供的默认构造函数的类的对象的值初始化将在默认初始化之前执行零初始化。
似乎the version of clang on Coliru在C++ 11之后一直在跟踪标准,但是GCC 4.8 has not。
编辑:This test program演示GCC 4.8确实遵循N3797规则进行值初始化。问题似乎在于它是默认初始化没有提供初始化程序的数组元素,而不是按标准要求对它们进行值初始化。请注意,第二个数组元素(显式提供一个空的初始化器)与第三个数组元素(不提供初始化器)之间的行为不同。
这看起来像是可能的GCC错误。
编辑:The same test program compiled by the same GCC version on Ideone没有演示该错误。不知道这是怎么回事。也许不同的编译器标志会影响Ideone上的输出,但我不知道如何确定所使用的编译器命令行。