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/end来rbegin/rend?
是的,这是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就好像它是&a[1][0]).这是一个或另一个.