c++language-lawyerpaddingmemory-alignment

Uses of pointer arithmetic within an object


Excerpt from the book "C++ memory management" by Patrice Roy

For example, the following code is correct, albeit not something one should seek to do (it makes no sense, and it does things in unnecessarily complicated ways, but it’s legal and does no harm):

struct A {
   int a;
   short s;
};

short * f(A &a) {
    // pointer interconvertibility in action!
    int *p = reinterpret_cast<int*>(&a);
    p++;
    return reinterpret_cast<short*>(p); // Ok, within the
                                       // same object
}

int main() {
    A a;
    short *p = f(a);
    *p = 3; // fine, technically
}

Author does not elaborate this statement. Is it correct from standard point of view and under what condition if so ?


Solution

  • I believe this is incorrect. Assuming for argument's sake that size and alignment and padding work out, which aren't checked, there is still a violation of pointer rules.

    reinterpret_cast between A* and int* works by the rules of pointer interconvertibility, and given a pointer to an A object, one can obtain a pointer to the int object which is its first member.

    So p is a valid pointer to an object basic.compound

    By expr.add, ++p results in a pointer "past the end" of the int member. Therefore, it represents the "first byte in memory after the end of the storage occupied by the object" but it does not point at the short. With the assumption that the address is the address of the short, we can try to get a pointer through std::launder. ptr.launder

    std::launder(reinterpret_cast<short*>(p))
    

    But this requires that all bytes reachable through the result are reachable through the initial pointer, which is not the case. basic.compound

    Therefore, the example is illegal.