Reputation: 9090
Is the following code legal in C++?
int get_i(int idx) { ... }
float transform(int i) { ... }
void use(float f) { ... }
static_assert(sizeof(int) == sizeof(float));
void* buffer = std::malloc(n * sizeof(int));
int* i_buffer = reinterpret_cast<int*>(buffer);
float* f_buffer = reinterpret_cast<float*>(buffer);
// Fill int values into the buffer
for(int idx = 0; idx < n; ++idx)
i_buffer[idx] = get_i(idx);
// Transform int value to float value, and overwrite
// (maybe violates strict aliassing rule?)
for(int idx = 0; idx < n; ++idx)
f_buffer[idx] = transform(i_buffer[idx]);
for(int idx = 0; idx < n; ++idx)
use(f_buffer[idx]);
The second step reads the buffer value as an int
, and then writes a float
in its place. It never accesses the memory through i_buffer
again afterwards, so there is no type aliasing when reading.
However the assignment f_buffer[idx] =
writes a float
object into an int
object, which is UB.
Is there a way to make the compiler consider this to mean that the lifetime of the int
should end, and a float
object should be constructed in its place, so that there is no type aliassing?
Upvotes: 0
Views: 100
Reputation: 136286
However the assignment
f_buffer[idx] =
writes a float object into an int object, which is UB.
Yep, the above breaks type aliasing rules.
To fix that, for your values you can use a union:
union U {
float f;
int i;
};
And then access the corresponding members of the union.
This way when you do:
buffer[idx].i = ...; // make i the active union member
...
buffer[idx].f = transform(buffer[idx].i); // make f the active union member
it avoids UB because lifetime of buffer[idx].i
ends and that of buffer[idx].f
starts.
Upvotes: 2