在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);
}
从技术上讲,我认为对于POD类型来说,以任何方式访问底层内存是合法的,但是std::*
的内容呢?
如果我将所有begin/end
更改为rbegin/rend
答案 0 :(得分:9)
是的,这是UB。
指针类型的每个值都是以下之一:
- 指向对象或函数的指针(指针指向对象或函数)或
- 指针超过对象的末尾([expr.add])或
- 该类型的空指针值([conv.ptr])或
- 指针值无效。
作为指向或超过对象末尾的指针的指针类型的值表示对象占用的内存中的第一个字节的地址([intro.memory])或结束后的内存中的第一个字节分别占用对象占用的存储空间。 [注意:超过对象末尾的指针([expr.add])不被视为指向可能位于该地址的对象类型的无关对象。当指示的存储达到其存储持续时间的末尾时,指针值变为无效;见[basic.stc]。 - 结束说明]
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型。如果表达式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
解释为{{1} }})。它是一个或另一个。