std::launder在placement new重用同一内存构造新对象后必须使用,否则通过原指针访问新对象将导致未定义行为;它不改变地址,仅重建指针与新对象的合法关联,且仅适用于刚由placement new构造的对象。

std::launder 什么时候必须用?
当你用 placement new 显式构造新对象到一块已存在(且未析构)的内存上,又想通过原指针访问新对象时,std::launder 就不是可选项——它是唯一符合标准的途径。否则行为未定义,哪怕代码看起来“跑通”了。
典型场景:对象池、variant 实现、自定义容器中复用内存。比如你 new (buf) T{1} 构造了一个 T,之后又在同一个 buf 上 new (buf) U{2} 构造了 U,此时若直接用原 static_cast<t>(buf)</t> 去读,编译器可能仍按旧类型 T 优化,或返回错误值。
- 不加
std::launder的指针,即使指向新对象的起始地址,也不被标准认定为“指向该对象” -
std::launder不改变地址,只告诉编译器:“请重新建立这个指针和它所指对象之间的关联” - 它只对指向“刚被 placement new 构造的对象”的指针有效;对普通堆分配、栈变量、或未构造内存调用是未定义的
std::launder 的参数和返回值怎么写?
函数签名是 template<class t> constexpr T* launder(T* p)</class>,传入什么类型指针,就返回同类型指针,不能隐式转换,也不能跨 cv 限定符乱来。
常见误写:
立即学习“C++免费学习笔记(深入)”;
- 传入
const void*或char*然后期望得到T*—— 不行,必须显式static_cast成目标类型的指针再传给std::launder - 对
const对象调用后,试图用返回的非const指针修改 —— 违反 const 正确性,编译报错 - 把
std::launder(&x)用于栈变量x—— 错误,&x指向的是自动存储期对象,不能被“替换”
正确示例:
char buf[sizeof(std::string)];
auto* s = new (buf) std::string("hello");
// ... 后续销毁 s->~string()
auto* i = new (buf) int(42);
int* safe_ptr = std::launder(reinterpret_cast<int*>(buf)); // ✅不用 std::launder 会出什么错?
不是每次都会崩溃,但风险真实存在:编译器可能做激进优化,比如把两次读取合并成一次,或缓存旧对象字段的值。尤其在 O2/O3 下,现象更隐蔽。
典型表现:
- 读到旧对象残留值(比如前一个对象的某个成员)
- UB 导致整个函数被优化掉(GCC/Clang 在某些条件下会这么做)
- AddressSanitizer 不报错,但 UndefinedBehaviorSanitizer 可能触发
undefined-behavior: object has been destroyed - 不同编译器结果不一致:MSVC 可能“碰巧”工作,Clang 更早暴露问题
注意:std::launder 本身不处理析构 —— 你仍需手动调用旧对象的析构函数,否则资源泄漏或双重析构风险仍在。
std::launder 和 std::memcpy / std::bit_cast 有什么区别?
std::launder 不复制、不解释比特,它只解决“指针合法性”问题;而 std::memcpy 是内存搬运,std::bit_cast 是无歧义的类型重解释(要求大小/对齐一致),三者完全不互换。
- 用
memcpy把一个T复制到U内存里,不代表你能安全地把那块内存当U用 —— 还得std::launder配合 placement new -
std::bit_cast<char>(42)</char>是合法的,但它不涉及对象生命周期,也不需要std::launder - 如果只是想“绕过类型系统读原始字节”,
reinterpret_cast+std::memcpy就够了;只有当你真正“替换了对象”,才轮到std::launder出场
最易忽略的一点:即使你确保了对齐、大小、triviality,只要没调用 std::launder,标准就不承认你拿到了新对象的合法指针 —— 这不是风格问题,是合规红线。








