问题
I was under the impression that while dereferencing pointers that don't point to a valid object is UB, simply computing such pointers is fine.
However, if I'm understanding expr.add[4] correctly, that's not the case.
So which of these pointer computations are well-defined?
int a = 42;
int *p = &a;
p; // valid, and obviously ok
p++; // invalid, but ok, because one past the end of 'array' containing 1 element?
p++; // UB ?
How about this case?
int *p = nullptr;
p; // invalid, and obviously ok (considered one past the end?)
p++; // one past the end? or UB?
回答1:
In your first example, the first p++
is well-defined, because a non-array is considered a one-length array.
Here's the relevant quote (basic.compound/3.4):
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.
After p++
, p
it will point past the last (and only) element of the (hypothetical) array, which is well-defined. It is not "invalid, but ok", as pointers pointing to past the end of an object are not invalid pointers, basic.compound/3.2:
Every value of pointer type is one of the following:
[...]
a pointer past the end of an object
[...]
an invalid pointer value.
The second p++
of the first example is UB, because the result will point after the hypothetical (&a)[1] element, which is not defined.
In your second example, p++
is UB, because only 0 can be added to a nullptr
(expr.add/4.1):
If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
[...]
Otherwise, the behavior is undefined.
来源:https://stackoverflow.com/questions/61296481/what-pointer-values-are-well-defined-to-compute