C++的 reinterpret_cast,以及放置new之后的严格别名规则

编程语言 2026-07-09

以下代码在C++标准下是未定义行为(UB),但许多类数组容器(如 std::vector)都是这样实现的,先使用 placement-new 再使用 reinterpret_cast<T*>

但根据C++的严格别名规则(参见 https://en.cppreference.com/cpp/language/reinterpret_cast),这是UB。

  1. p0532r0表示 std::launder() 不能解决这个问题;
  2. std::start_lifetime_as() 似乎也不能解决这个问题;
  3. p0593r6 ?
struct T { int x; };

alignas(T) std::byte buffer[sizeof(T)];

// 1. Placement new to create the object

new(buffer) T{42};       // #obj1

// question: how to get `#obj1` by buffer pointer ?

T *t = reinterpret_cast<T*>(buffer);

auto obj1 = t[0];             // UB: T does not alias std::byte; (strict aliasing);

问题:

  1. 标准中的哪一条规定会让上述代码成为定义行为?
  2. 否则,像 std::vector-那样的容器如何让这些问题变得正确?

解决方案

感谢所有的评论和回答,我认为 @Artyer的方向是正确的,但如果元素类型不是const,则不需要std::launder()。

下面就一些可能的疑问来回答:

  1. Object lifetime and Providing storage 使相关底层字节的生命周期在对其对应地址使用placement new(T) 时隐式结束。
  2. reinterpret_cast保证 T * -> char * -> T * 回到原始值(例如由placement new(T) 返回的值)。(https://en.cppreference.com/cpp/language/reinterpret_cast#Explanation) (list 5)
  3. T对自身是 type-accessible 的。

并且,

  1. std::launder() 解决的问题与此不同;(Map> 中的const应如何处理?)
  2. start_lifetimes_as() 适用于平凡类型,如聚合类型,而不是用于placement new和一般情况;
  3. 严格别名规则不适用,因为在使用placement new之后,该地址上已经开始了一个活动对象的生命周期,因此把它的地址转换为字节指针再转换回来并不会产生UB。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章