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

时间:2018-10-04 09:44:59

标签: c++ strict-aliasing

以下代码在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对象写入UB的int对象中。

有没有一种方法可以使编译器认为这意味着int的生存期应该结束,并且应该在其位置构造一个float对象,以便没有类型混叠。 ?

1 个答案:

答案 0 :(得分:2)

  

然而,赋值f_buffer[idx] =将一个float对象写入一个int对象即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的生存期开始了。