C++ 是标准定义的std::数组的大小

C++ 是标准定义的std::数组的大小,c++,c++11,stl,language-lawyer,C++,C++11,Stl,Language Lawyer,在C++11中,std::array被定义为具有连续存储且性能不比数组差,但我无法确定标准的各种要求是否意味着std::array具有与普通数组相同的大小和内存布局。也就是说,您可以依赖于sizeof(std::array)==sizeof(int)*N,或者该实现是特定的吗 特别是,这是否保证以您期望的方式工作: std::vector< std::array<int, N> > x(M); typedef (*ArrayPointer)[N]; ArrayPointe

在C++11中,std::array被定义为具有连续存储且性能不比数组差,但我无法确定标准的各种要求是否意味着std::array具有与普通数组相同的大小和内存布局。也就是说,您可以依赖于
sizeof(std::array)==sizeof(int)*N
,或者该实现是特定的吗

特别是,这是否保证以您期望的方式工作:

std::vector< std::array<int, N> > x(M);
typedef (*ArrayPointer)[N];
ArrayPointer y = (ArrayPointer) &x[0][0];
// use y like normal multidimensional array
std::vectorx(M);
typedef(*ArrayPointer)[N];
阵列指针y=(阵列指针)&x[0][0];
//使用类似于普通多维数组的y
它在我尝试过的两个编译器(GNU和Intel)中工作。此外,我能找到的所有第三方文档()都说明std::array与普通数组一样具有内存效率,这与连续性要求相结合意味着它必须具有相同的内存布局。但是,我在标准中找不到这一要求。

这几乎是必需的。具体而言,§23.3.2.1/2规定:

数组是可以使用以下语法初始化的聚合(8.5.1)

数组a={初始值设定项列表};
其中,
初始值设定项列表
是一个逗号分隔的列表,最多包含N个类型可转换为T的元素

由于它是一个聚合,因此不能使用任何类型的构造函数将初始值设定项列表中的数据转换为正确的格式。这实际上只剩下一种可能性:它能存储的唯一东西就是价值本身

我认为
std::array
可能会在指定数据之后存储某种辅助数据,例如设置为某个预定义值的额外内存,因此,如果写入超过数组末尾,则可能会更改该数据。然后,编译器/运行时将在关闭时检查这些值,如果您更改了这些值,则报告代码的未定义行为

编译器对
std::array
的填充/对齐方式也可能与对内置数组的填充/对齐方式不同。一个明显的例子是支持超级对齐要求,例如用于英特尔SSE指令的数据。内置数组不能支持超级对齐,但我认为
std::array
的规范可能不够宽松,不足以支持超级对齐


一句话:在不讨论可能存在多少可能性的情况下,很明显,
std::array
不一定要遵循您所问的规则。

23.3.2类模板数组中没有这样的保证,事实上,在标准中搜索
sizeof
似乎只能为我找到以下保证:
char
及其变体是
1
nullptr
具有与
void*
相同的sizeof。正如@us2012所述,没有明确的保证。虽然它可以在您选择的平台上工作,但在具有不同对齐约束的其他平台上可能会失败。我想您可以简单地对代码中的所有类型使用
static\u断言(sizeof(std::array)==sizeof(T)*N)
作为tripwire,以实现不同寻常的库实现(或导致
std::array
以不同方式对齐的某个对齐选项)。如果大小相等,则布局必须相同。我认为它也可以有填充,即使在开始时也是如此,因为它不需要是标准布局类(也不能是,因为其成员可能是非标准布局类型)。(是的,这并不能证明什么。我仔细搜索了标准,没有发现聚合或文字类型的任何布局要求,只找到了标准布局类型;以前PODs在C++03中有这些要求。)C禁止结构在6.7.2.1/15中开始时有未命名的填充“结构对象中可能有未命名的填充,但不是在它的开头。”(即,你仍然可以在结尾处有它)是的——重读一些东西,我认为你是对的——在开头也可能有未命名的填充。你可能也感兴趣,特别是考虑到
0
std::array
的特例。
array<T, N> a = { initializer-list };