Search code examples
c++arrayspointersc++17language-design

Pointer interconvertibility vs having the same address


The working draft of the standard N4659 says:

[basic.compound]
If two objects are pointer-interconvertible, then they have the same address

and then notes that

An array object and its first element are not pointer-interconvertible, even though they have the same address

What is the rationale for making an array object and its first element non-pointer-interconvertible? More generally, what is the rationale for distinguishing the notion of pointer-interconvertibility from the notion of having the same address? Isn't there a contradiction in there somewhere?

It would appear that given this sequence of statements

int a[10];

void* p1 = static_cast<void*>(&a[0]);
void* p2 = static_cast<void*>(&a);

int* i1 = static_cast<int*>(p1);
int* i2 = static_cast<int*>(p2);

we have p1 == p2, however, i1 is well defined and using i2 would result in UB.


Solution

  • There are apparently existing implementations that optimize based on this. Consider:

    struct A {
        double x[4];
        int n;
    };
    
    void g(double* p);
    
    int f() {
        A a { {}, 42 };
        g(&a.x[1]);
        return a.n; // optimized to return 42;
                    // valid only if you can't validly obtain &a.n from &a.x[1]
    }
    

    Given p = &a.x[1];, g might attempt to obtain access to a.n by reinterpret_cast<A*>(reinterpret_cast<double(*)[4]>(p - 1))->n. If the inner cast successfully yielded a pointer to a.x, then the outer cast will yield a pointer to a, giving the class member access defined behavior and thus outlawing the optimization.