使用公共迭代器访问数组数组的元素

Ori*_*ent 10 c++ arrays stl language-lawyer

是否在C++中使用未定义的行为来访问相邻数组中的元素,如下面的代码所示?

#include <type_traits>
#include <algorithm>
#include <iterator>

int main()
{
    int a[10][10];
    static_assert(std::is_standard_layout< decltype(a) >::value, "!");
    std::fill(std::begin(*std::begin(a)), std::end(*std::prev(std::end(a))), 0);
    struct B { int b[10]; };
    B b[10];
    static_assert(std::is_standard_layout< decltype(b) >::value, "!");
    std::fill(std::begin(std::begin(b)->b), std::end(std::prev(std::end(b))->b), 0);
}
Run Code Online (Sandbox Code Playgroud)

从技术上讲,我认为对于POD类型来说,以任何方式访问底层内存是合法的,但是那些std::*东西呢?

如果我改变一切什么begin/endrbegin/rend

Bar*_*rry 9

是的,这是UB.

来自[basic.compound]:

指针类型的每个值都是以下之一:

  • 指向对象或函数的指针(指针指向对象或函数),或
  • 指针超过对象的末尾([expr.add]),或
  • 该类型的空指针值([conv.ptr]),或
  • 无效的指针值.

指针类型的值是指向或超过对象末尾的指针,表示对象占用的内存中的第一个字节的地址([intro.memory])或存储结束后的内存中的第一个字节分别被对象占用.[注意:超过对象末尾的指针([expr.add])不被视为指向可能位于该地址的对象类型的无关对象.当指示的存储达到其存储持续时间的末尾时,指针值变为无效; 见[basic.stc]. - 结束说明]

[expr.add]/4:

当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型.如果表达式P指向具有n个元素的数组对象x的元素x [i],则86表达式P + J和J + P(其中J具有值j)指向(可能是假设的)元素x [i + j]如果0≤i+j≤n; 否则,行为未定义.同样地,如果0≤i-j≤n,则表达式P-J指向(可能是假设的)元素x [i-j]; 否则,行为未定义.

所以&a[0][0] + 10是"指针越过一个对象的末尾",它是过去第一个数组的结束指针.你不能再向该指针添加一个 - 这种情况没有定义的行为.

一个指针不能是两者是"过去的结束"指针一个"指针到对象"(解释&a[0][0] + 10就好像它是&a[1][0]).这是一个或另一个.