C++ 类型别名,其中值被替换

C++ type aliasing, where value is replaced

以下代码在 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]);

第二步将缓冲区值读取为int,然后在其位置写入float。之后它再也不会通过 i_buffer 访问内存,因此读取时没有类型别名。

但是赋值 f_buffer[idx] = 将一个 float 对象写入一个 int 对象,即 UB。

有没有办法让编译器认为这意味着 int 的生命周期应该结束,并且应该在它的位置构造一个 float 对象,这样就没有了键入别名?

However the assignment f_buffer[idx] = writes a float object into an int object, which is UB.

是的,以上中断 type aliasing rules

要解决这个问题,对于您的值,您可以使用联合:

union U {
    float f;
    int i;
};

然后访问对应的工会会员

这样当你做的时候:

buffer[idx].i = ...; // make i the active union member
...
buffer[idx].f = transform(buffer[idx].i); // make f the active union member

它避免了 UB,因为 buffer[idx].i 的生命周期结束,buffer[idx].f 的生命周期开始。