placement new存储区类型限制及相关代码合法性技术问询
问题1:存储提供者是否必须为char、unsigned char或std::byte类型,还是可以为任意类型?
不是必须限定为这三种类型,但char、unsigned char、std::byte是最安全的选择。
C++标准允许使用其他类型的数组作为对象的存储载体,但需要满足以下条件:
- 存储的总字节数至少能容纳目标类型
T的对象; - 存储的对齐要求不低于
T的对齐要求; - 如果存储的原类型是非平凡类型,需要先结束原对象的生存期(比如显式调用析构函数);
- 原类型的存储不能包含陷阱表示(即任何位模式都是合法值)。
而char、unsigned char、std::byte的特殊之处在于:它们没有陷阱表示,且允许隐式结束其生存期以容纳新对象,因此作为存储提供者时不需要额外处理这些边界情况。
问题2:以下C++代码是定义良好行为(well-defined)还是未定义行为(UB)?
alignas(alignof(T)) char buffer[sizeof(T)]; auto* p = new(buffer) T; // use p p->~T(); // destroy at end
这段代码是定义良好的。
理由如下:
char数组的大小sizeof(T)足够容纳T类型的对象;alignas(alignof(T))确保了数组的对齐要求满足T的对齐需求;- placement new的使用符合规范,正确在
buffer的存储上构造了T对象; - 最后显式调用了
T的析构函数,正确结束了对象的生存期。
整个流程完全符合C++标准对对象生存期管理的要求,没有未定义行为。
问题3:上述代码中的buffer是否必须为char、unsigned char或std::byte类型,还是可以为int这类任意类型?
alignas(alignof(T)) int buffer[sizeof(T)/(sizeof(*buffer) + ((sizeof(T)%sizeof(*buffer)!=0)];
注:原代码的数组大小表达式存在语法错误,正确的写法应为sizeof(T)/sizeof(*buffer) + (sizeof(T)%sizeof(*buffer) != 0 ? 1 : 0),确保总字节数至少等于sizeof(T)。
可以使用int这类类型作为存储,但需要满足几个关键条件:
- 存储大小足够:数组的总字节数(数组长度 × sizeof(int))必须大于等于
sizeof(T); - 对齐要求满足:通过
alignas(alignof(T))确保数组的对齐不低于T的对齐需求; - 原对象生存期处理:
int是平凡类型,当用placement new在其存储上创建T对象时,原int对象的生存期会自动结束。如果使用的是非平凡类型的数组,则需要先显式调用原对象的析构函数; - 无陷阱表示:所用类型(如
int)在目标平台上不存在陷阱表示(即所有位模式都是合法的对象值)。
不过相比之下,char、unsigned char、std::byte仍然是更稳妥的选择:它们没有陷阱表示,且不需要考虑原对象生存期的额外处理,代码的可移植性和安全性更高。
内容的提问来源于stack exchange,提问作者user24551355
相关产品推荐
相关产品推荐

