【问题标题】:Is the data in nested std::arrays guaranteed to be contiguous?嵌套的 std::arrays 中的数据是否保证是连续的?
【发布时间】:2012-04-03 11:53:04
【问题描述】:

std::array<std::array<T,N>, M> 中的数据是否保证是连续的?例如:

#include <array>
#include <cassert>

int main()
{
    enum {M=4, N=7};
    typedef std::array<char,N> Row;
    typedef std::array<Row, M> Matrix;
    Matrix a;
    a[1][0] = 42;
    const char* data = a[0].data();

    /* 8th element of 1D data array should be the same as
       1st element of second row. */
    assert(data[7] == 42);
}

断言是否保证成功?或者,换句话说,我可以依靠Row 的末尾没有填充吗?

编辑:为了清楚起见,对于这个例子,我希望整个矩阵的数据是连续的。

【问题讨论】:

  • 即使存储是连续的,我相信您也会违反别名规则。请参阅我在很多个月前问过的这个问题(诚然,关于 C):stackoverflow.com/questions/6290956/…
  • Is the memory in std::array contiguous? 可能通过递归复制
  • @LightnessRacesinOrbit :不,我不认为这是重复的。虽然单个std::array 中的数据是连续的,但这并不意味着嵌套std::arrays 中的整个数据集是连续的。或者至少对于像我这样的非语言律师来说并不明显。
  • @Emile:是的,确实如此。如果std::array 中的每个元素都是连续的,那么这意味着std::array&lt;std::array&lt;..&gt;&gt; 中的每个std::array 都直接与下一个元素相邻。而且,通过递归,每个“sub”-std::arrays 也是连续的。容器不会因为它是它自己的value_type 而突然而神奇地失去连续性(如果确实是容器的保证)。 [编辑:但是,这与最里面的Ts 不同,它们都彼此相邻。看来这就是你的意思,所以,很好:P]
  • @LightnessRacesinOrbit :就像詹姆斯在他的回答中所说的那样,array&lt;T&gt; 的末尾不需要填充或额外的数据成员,尽管我承认体面的实现不会这样做一件事。

标签: c++ multidimensional-array c++11


【解决方案1】:

它们很可能是连续的。如果不是,编译器正在那里积极地与你作战。不能保证它不会插入填充,但几乎没有理由。

断言是否保证成功?

data[7] 是越界访问(未定义行为)。内部数组对象只有七个元素,因此索引 7 无效。

【讨论】:

  • 嗯,你的回答似乎有点矛盾(或者我太密集了)。如果数据是连续的,data[7]不会指向第二行的第一个元素吗?
  • @Emile 认为“一维数据数组的第 8 个元素应该与第二行的第一个元素相同”的缺陷。忽略了该代码中没有数组有第 8 个元素。因此,无法保证 data[7] 会做什么。实际上,是的,我怀疑它会指向第二行的第一个元素,但与 UB 一样,你不能安全地依赖它
  • 好的,那我取“它们很可能是连续的”来表示每个内部数组中的数据是连续的。这是你的意思吗?
  • 并且每个内部数组也是相互连续的。但是在索引时,您不能从一个交叉到另一个。这不是std::array 的事情。 int x[4][7]; int* xp = x; xp[7]; 也是如此。 “它们很可能是连续的”我的意思是没有理智的编译器会插入任何填充。
  • @Emile:为了清楚起见,回到你原来的问题:我不介意依赖没有填充(我不想支持像这样疯狂的东西的编译器那!),因为它实际上可以被测试:static_assert(sizeof(Matrix) == sizeof(char)*M*N, "nested std::arrays should have no padding");。我更厌倦了将索引作为一个大数组依赖,因为它无法测试(它现在可能工作并且通常会工作,但当优化器决定利用它进行优化时可能会失败)。
【解决方案2】:

不,在这种情况下不能保证连续性。

std::array 保证是一个聚合,并以这样一种方式指定,即用于存储的底层数组必须是该类型的第一个数据成员。

但是,没有要求 sizeof(array&lt;T, N&gt;) == sizeof(T) * N,也没有要求在对象末尾没有未命名的填充字节,或者 std::array 除了底层数组存储之外没有任何数据成员。 (不过,包含额外数据成员的实现充其量是不寻常的。)

【讨论】:

    猜你喜欢
    • 2014-01-21
    • 2010-10-25
    • 1970-01-01
    • 2011-02-19
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 2011-10-01
    相关资源
    最近更新 更多