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
的生命周期开始。
以下代码在 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
的生命周期开始。