能否将placement new用于类数组?代码用法合规吗?reinterpret_cast是否致UB?
代码分析与问题解答
这段代码存在未定义行为,但问题根源并非reinterpret_cast,而是对象对齐不满足要求导致placement new构造double时就已触发UB;即使对齐问题解决,reinterpret_cast本身合法,但必须配合std::launder才能正确访问新对象。
核心问题拆解
1. 对齐不匹配导致的未定义行为
Block结构体使用alignas(int)指定对齐要求,意味着Block类型的对齐值等于int的对齐值(通常为4字节)。- 数组
buff的对齐要求继承自Block,因此buff的起始地址仅保证按int对齐。 - 在绝大多数系统中,
double的对齐要求高于int(比如64位系统中double需要8字节对齐),此时&buff的地址无法满足double的对齐要求。根据C++标准,使用placement new构造对象时,目标地址必须满足该对象的对齐要求,否则行为完全未定义。
2. reinterpret_cast的合法性分析
假设我们修正对齐问题(比如将Block的对齐改为alignas(double)),此时:
reinterpret_cast<double*>(&buff)本身是合法的:它将指向Block数组的指针转换为double*,只要转换后的指针值是double对象的有效地址(这里就是新构造的double的起始地址),这种转换符合C++标准对reinterpret_cast的规则。- 必须使用
std::launder:因为原指针指向的是Block数组对象,而我们在其存储上构造了全新的double对象,std::launder用于告知编译器,该指针现在指向的是一个与原对象类型不同的新对象,从而规避strict aliasing规则带来的未定义行为。
修正后的示例代码
struct Block { alignas(double) unsigned char data[sizeof(int)]; // 修正对齐要求 }; int main() { Block buff[sizeof(double) / sizeof(int)]; ::new(&buff) double(); double d = *std::launder(reinterpret_cast<double*>(&buff)); return 0; }
内容的提问来源于stack exchange,提问作者ValueError
相关产品推荐
相关产品推荐

