Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access to elements of array of arrays using common iterator

Is it undefined behaviour in C++ to access elements in adjacent arrays as in following code?

#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);
}

Technically I think for POD-types it is legal to access underlying memory in any manner one want, but what about std::* stuff?

What if I change all begin/end to rbegin/rend?

like image 680
Tomilov Anatoliy Avatar asked Mar 08 '18 13:03

Tomilov Anatoliy


1 Answers

Yes, this is UB.

From [basic.compound]:

Every value of pointer type is one of the following:

  • a pointer to an object or function (the pointer is said to point to the object or function), or
  • a pointer past the end of an object ([expr.add]), or
  • the null pointer value ([conv.ptr]) for that type, or
  • an invalid pointer value.

A value of a pointer type that is a pointer to or past the end of an object represents the address of the first byte in memory ([intro.memory]) occupied by the object or the first byte in memory after the end of the storage occupied by the object, respectively. [ Note: A pointer past the end of an object ([expr.add]) is not considered to point to an unrelated object of the object's type that might be located at that address. A pointer value becomes invalid when the storage it denotes reaches the end of its storage duration; see [basic.stc]. — end note ]

And [expr.add]/4:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements,86 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i+j] if 0≤i+j≤n; otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x[i−j] if 0≤i−j≤n ; otherwise, the behavior is undefined.

So &a[0][0] + 10 is a "pointer past the end of an object", it's the past the end pointer of the first array. You cannot add one more to that pointer - there is no defined behavior for this case.

A pointer cannot be both a "past the end" pointer and a "pointer to object" (interpreting &a[0][0] + 10 as if it were &a[1][0]). It's one or the other.

like image 144
Barry Avatar answered Nov 04 '22 01:11

Barry