【问题标题】:Is the size of std::array defined by standardstd::array 的大小是否由标准定义
【发布时间】:2013-10-06 20:22:32
【问题描述】:

在 C++11 中,std::array 被定义为具有不比数组差的连续存储和性能,但我无法确定标准的各种要求是否意味着 std::array 具有相同的大小和内存布局作为普通数组。那就是你可以指望sizeof(std::array<int,N>) == 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

它适用于我尝试过的两个编译器(GNU 和英特尔)。此外,我能找到的所有第 3 方文档 (like this) 都指出 std::array 与普通数组一样具有内存效率,结合连续要求意味着它必须具有相同的内存布局。但是我在标准中找不到这个要求。

【问题讨论】:

  • 23.3.2 Class template array 中没有这样的保证,事实上,搜索sizeof 的标准似乎只会为我找到以下保证:char 及其变体是1nullptr 的 sizeof 与 void* 相同。
  • 正如@us2012 所说,没有明确的保证。虽然它可能在您选择的平台上运行,但在具有不同对齐约束的其他平台上可能会失败。
  • 我想您可以简单地将代码中所有类型的static_assert(sizeof(std::array&lt;T,N&gt;) == sizeof(T)*N) 用作异常库实现的绊线(或导致std::array 以不同方式对齐的某些对齐选项)。如果大小相等,则布局必须相同。

标签: c++ c++11 stl language-lawyer


【解决方案1】:

几乎需要。具体来说,§23.3.2.1/2 说:

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

array<T, N> a = { initializer-list };

其中initializer-list 是一个逗号分隔的列表,最多包含 N 个元素,其类型可转换为 T。

由于它是一个聚合,它不能使用任何类型的构造函数将初始化列表中的数据转换为正确的格式。那真的只剩下一种可能性:它唯一可以存储的就是值本身。

我想 std::array 有可能在指定数据之后存储某种辅助数据,例如设置为某个预定义值的额外内存,所以如果你写到最后在数组中,您可能会更改该数据。编译器/运行时将在关闭时检查这些值,如果您更改了这些值,请报告代码的未定义行为。

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

底线:不涉及可能存在多少种可能性的问题,很明显std::array 不一定必须遵循您所询问的规则。

【讨论】:

  • 我认为它也可以有填充,即使在开始时,因为它不需要是标准布局类(也不能,因为它的成员可能是非标准的-布局类型)。
  • Live example (是的,这并不能证明什么。我仔细搜索了标准并没有找到聚合或文字类型的任何 layout 要求,仅适用于标准-布局类型;以前的 POD 在 C++03 中有这些要求。)
  • C 禁止结构在 6.7.2.1/15 的开头有未命名的填充“结构对象中可能有未命名的填充,但不是在其开头。” (即最后你仍然可以拥有它)
  • 是的——重读东西,我认为你是对的——开头也可能有未命名的填充。
  • 您可能也对this 感兴趣,尤其是考虑到0std::array 的一个特例。
猜你喜欢
  • 2020-05-20
  • 1970-01-01
  • 2015-12-24
  • 2017-02-17
  • 1970-01-01
  • 1970-01-01
  • 2016-03-27
  • 1970-01-01
相关资源
最近更新 更多