ISO IEC 14882-2011 §5.7/5 States:
If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
This section is used here on stackoverflow from time to time. For instance to argue why the increment of a pointer to nullptr
is UB like here. It is then interpreted as, having a pointer that does not point to an element of an array object. Is undefined behaviour.
However, when I read this I understood it to refer to the evaluation of the pointer being UB. Which would mean that having such a pointer is well defined behaviour. And the behaviour becomes undefined when one tries to dereference it.
Which would mean that for example, incrementing a valid pointer beyond the array boundary is legal. Decrementing it again afterwards is legal. And since the pointer will then be the same value as before the increment, the evaluation is legal too.
Which of the two is the case?
The paragraph you're quoting refers to pointer arithmetic, not to evaluation of pointers.
It states that the only time pointer addition p + i
is defined is if
(treating subtraction of i
as equivalent to addition of -i
)
p
points to an element of an array object or one past the last element, and
p + i
points to an element of the same array object, or one past the last element
If p
isn't a pointer to an array element or "one past the end" - for instance if it is the null pointer or "two past the end" - the behaviour is undefined.
You don't need to dereference the result to cause undefined behaviour - the effect of the addition itself is undefined.
That is to say
int p[1] = {0};
int *q = p; // OK
q = q + 1; // OK - one past the end
int *r = q + 1; // Undefined behaviour
r = r - 1; // Doesn't make r valid or the program un-undefined
and likewise
int *p = nullptr;
p++; // Undefined
p--; // Still undefined
"The evaluation" means the evaluation of the additive operation; thus UB would not occur for (say) static_cast<int*>(nullptr) + 1
within a non-evaluated context (sizeof
, decltype
, etc).
It does not mean "the evaluation of the pointer", and certainly not dereferencing it; if the standard had intended that interpretation, it would have said so.
Incrementing then decrementing a null pointer is still undefined behaviour. When UB occurs, anything can happen, so this would be a valid sequence of an events:
- Increment null pointer. Undefined behaviour, so we'll set the pointer to
0xDEADBEEF
because we can.
- Decrement pointer. Also undefined behaviour unless
0xDEADBEEF
happens to be in a valid array after the first element.
- Dereference pointer. Issue forth nasal demons.