Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is creating a pointer one past the end of a non-array pointer not derived from unary operator & undefined behavior in C++17?

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.

like image 764
0x5f3759df Avatar asked Jun 18 '18 18:06

0x5f3759df


People also ask

Can a pointer point one past the end of an object?

it is possible for a pointer to an object and a pointer one past the end of a different object to hold the same address.

Is a pointer always an array?

An array is a pointer. An array is considered to be the same thing as a pointer to the first item in the array. That rule has several consequences. An array of integers has type int*.

Is a pointer to a pointer an array?

Pointer to an array: Pointer to an array is also known as array pointer. We are using the pointer to access the components of the array. int a[3] = {3, 4, 5 }; int *ptr = a; We have a pointer ptr that focuses to the 0th component of the array.

Can we create pointers to arrays?

C. In this program, we have a pointer ptr that points to the 0th element of the array. Similarly, we can also declare a pointer that can point to whole array instead of only one element of the array. This pointer is useful when talking about multidimensional arrays.


1 Answers

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.

8.5.2.1 [expr.unary.op]

[...] 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.

like image 159
Yakk - Adam Nevraumont Avatar answered Oct 17 '22 10:10

Yakk - Adam Nevraumont