-->

Is one-past-end pointer OK for non-array object ty

2020-07-11 05:20发布

问题:

Is this valid C++?

int main()
{
    int i = 0;
    int* pi = &i;
    ++pi;
}

I know that one-past-end pointers are allowed for array types, but I'm not sure in this case. Does that code technically have undefined behavior?

回答1:

Yes, it is okay. It is one of the four categories of values any pointer type may hold.

[basic.compound] (emphasis mine)

3 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 ] For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), a pointer past the end of the last element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical array element n of x and an object of type T that is not an array element is considered to belong to an array with one element of type T.

As you can see, array types are also mentioned here, with their hypothetical object past the end. And as the footnote in [expr.add] explains, the arithmetic to obtain a one-past-the-end pointer is meant to be valid too:

As specified in [basic.compound], an object that is not an array element is considered to belong to a single-element array for this purpose and a pointer past the last element of an array of n elements is considered to be equivalent to a pointer to a hypothetical array element n for this purpose.