嵌套的std::arrays中的数据是否保证是连续的?

17

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语言,诚然):https://dev59.com/gW015IYBdhLWcg3w9wl1。 - Oliver Charlesworth
可能是std::array中的内存连续吗?的重复问题,由recursion提出。 - Lightness Races in Orbit
3
不,我不认为这是重复的。虽然单个std::array中的数据是连续的,但这并不意味着嵌套的std::array中的整个数据集是连续的。至少对于像我这样的非语言专家来说,这并不明显。 - Emile Cormier
1
@Emile:是的,确实如此。如果std::array中的每个元素都是连续的,那么意味着在std::array<std::array<..>>中的每个std::array直接相邻。通过递归,这些“子”std::array也是连续的。一个容器并不会因为它是自己的value_type而突然失去连续性(如果确实是容器的保证)。_[编辑:但是,这并不意味着最内层的T都彼此连续。看来这正是你想表达的,所以没问题 :P]_ - Lightness Races in Orbit
@LightnessRacesinOrbit:就像James在他的答案中所说,array<T>的末尾并没有要求不含填充或额外数据成员,尽管我承认像样的实现不会这么做。 - Emile Cormier
2个回答

19
不,这种情况下并不能保证连续性。
std::array被保证为聚合体,并且被规定为用于存储的基础数组必须是类型的第一个数据成员。
然而,并没有要求sizeof(array) == sizeof(T) * N,也没有要求对象末尾没有未命名的填充字节或者std::array除了基础数组存储之外没有其他数据成员。(尽管,包含其他数据成员的实现最多只能算是不寻常。)

5

它们很有可能是连续的。如果它们不是连续的,编译器就会与您作对。没有保证它不会插入填充,但几乎没有理由这样做。

assert断言能够成功吗?

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


@Emile,这种“一维数据数组的第8个元素应该与第二行的第一个元素相同”的想法中存在的缺陷是忽略了代码中没有任何数组有第8个元素。因此,无法保证data[7]会做什么。实际上,我认为它可能指向第二行的第一个元素,但是由于UB的原因,您不能安全地依赖它 - R. Martinho Fernandes
好的,那么我认为“they are very likely contiguous”的意思是每个内部数组中的数据是连续的。这是你的意思吗? - Emile Cormier
我并不是说这是错误的,但对我来说似乎有些违反直觉。如果int x[4][7]是连续的,那么(对我来说)数据在内存中占据了28个连续的sizeof(int)字节的插槽。如果我执行xp[7](相当于*(xp+7)),那么它应该只是解引用这28个连续插槽中的第8个插槽。索引和指针算术后跟随解引用是否不同? - Emile Cormier
@Emile 是的,它将与一个具有28个元素(如int x[28])的大数组对象具有相同的内存布局。但是并不存在“一个具有28个元素的大数组”。有一个具有4个元素和四个具有7个元素的数组。它可能会工作,但标准不提供任何保证。 - R. Martinho Fernandes
1
@Emile:只是为了明确,回到你最初的问题上来:我不介意依赖于没有填充(我不想支持那些做疯狂事情的编译器!),因为它实际上可以测试:static_assert(sizeof(Matrix) == sizeof(char)*M*N, "nested std::arrays should have no padding");。我更加警惕依赖于将索引作为一个大数组,因为这不能被测试(现在可能工作并且通常会,但当优化器决定利用它进行优化时,它可能以后失败)。 - R. Martinho Fernandes
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接