'Is it legal to cast a pointer to array reference using static_cast in C++?

I have a pointer T * pValues that I would like to view as a T (&values)[N]

In this SO answer https://stackoverflow.com/a/2634994/239916, the proposed way of doing this is

T (&values)[N] = *static_cast<T(*)[N]>(static_cast<void*>(pValues));

The concern I have about this is. In his example, pValues is initialized in the following way

T theValues[N];
T * pValues = theValues;

My question is whether the cast construct is legal if pValues comes from any of the following constructs:

1:

T theValues[N + M]; // M > 0
T * pValues = theValues;

2:

T * pValues = new T[N + M]; // M >= 0


Solution 1:[1]

Since C++17 at least the shown expression isn't safe, even if pValues is a pointer to the first element of the array and the array is of exactly matching type (including excat size), whether obtained from a variable declaration or a call to new. (If theses criteria are not satisfied it is UB regardless of the following.)

Arrays and their first element are not pointer-interconvertible and therefore reinterpret_cast (which is equivalent to two static_casts through void*) cannot cast the pointer value of one to a pointer value of the other.

Consequently static_cast<T(*)[N]>(static_cast<void*>(pValues)) will still point at the first element of the array, not the array object itself.

Derferencing this pointer is then undefined behavior, because of the type/value mismatch.

This can be potentially remedied with std::launder, which may change the pointer value where reinterpret_cast can't. Specifically the following may be well-defined:

T (&values)[N] = *std::launder(static_cast<T(*)[N]>(static_cast<void*>(pValues)));

or equivalently

T (&values)[N] = *std::launder(reinterpret_cast<T(*)[N]>(pValues));

but only if the pointer that would be returned by std::launder cannot be used to access any bytes that weren't accessible through the original pValues pointer. This is satified if the array is a complete object, but e.g. not satisfied if the array is a subarray of a two-dimensional array.

For the exact reachability condition, see https://en.cppreference.com/w/cpp/utility/launder.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user17732522