Reputation: 2359
The C++17 standard seems to say that an integer can only be added to a pointer if the pointer is to an array element, or, as a special exception, the pointer is the result of unary operator &
:
8.5.6 [expr.add] describing addition to a pointer:
When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤ n; otherwise, the behavior is undefined.
This quote includes a non-normative footnote:
An object that is not an array element is considered to belong to a single-element array for this purpose; see 8.5.2.1
which references 8.5.2.1 [expr.unary.op] discussing the unary &
operator:
The result of the unary & operator is a pointer to its operand... For purposes of pointer arithmetic (8.5.6) and comparison (8.5.9, 8.5.10), an object that is not an array element whose address is taken in this way is considered to belong to an array with one element of type T.
The non-normative footnote seems to be slightly misleading, as the section it references describes behavior specific to the result of unary operator &
. Nothing appears to permit other pointers (e.g. from non-array new
) to be considered single-element arrays.
This seems to suggest:
void f(int a) {
int* z = (new int) + 1; // undefined behavior
int* w = &a + 1; // ok
}
Is this an oversight in the changes made for C++17? Am I missing something? Is there a reason that the "single-element array rule" is only provided specifically for unary operator &
?
Note: As specified in the title, this question is specific to C++17. The C standard and prior versions of the C++ standard contained clear normative language that is no longer present. Older, vague questions like this are not relevant.
Upvotes: 15
Views: 407
Reputation: 275820
Yes, this appears to be a bug in the c++17 standard.
int* z = (new int)+1; // undefined behavior.
int* a = new int;
int* b = a+1; // undefined behavior, same reason as `z`
&*a; // seeming noop, but magically makes `*a` into an array of one element!
int* c = a+1; // defined behavior!
this is pretty ridiculous.
[...] an object that is not an array element whose address is taken in this way is considered to belong to an array with one element of type T
once "blessed" by 8.5.2.1, the object is an array of one element. If you don't bless it by invoking &
at least once, it has never been blessed by 8.5.2.1 and is not an array of one element.
It was fixed as a defect in c++20.
Upvotes: 7