You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在const对象自身位置重建对象:返回值与UB问题探讨

const对象销毁后重建的行为与std::launder使用解析

在以下场景中:调用析构函数结束const对象s的生命周期,随后在同一内存位置创建同类型S的新对象。由于违反了[basic.life]/8.3规则(针对const对象的限制),访问新创建的S对象必须使用std::launder。

#include <new>
#include <utility>

struct S {
    int x;
};

template <class T, class... Pars>
void Recreate(const T& value, Pars&&... pars) {
    value.~T();
    new(const_cast<T*>(&value)) T(std::forward<Pars>(pars)...);
}

int main() {
    const S s(1);
    Recreate(s, 2);
    return std::launder(&s)->x;
}

问题解答

  1. 程序的返回值与是否存在未定义行为
    这个程序没有未定义行为,且必须返回2。
    当Recreate(s, 2)执行时,原const对象s被销毁,同一块内存上重建了值为2的新S对象。由于原对象是const限定类型,根据C++标准[basic.life]/8.3的规则,原对象的名字s无法自动关联到新对象,此时必须通过std::launder来获取指向新对象的合法指针。示例中std::launder(&s)->x的写法是合规的,std::launder调整指针后,程序可以合法访问新对象的成员x,因此返回值必然是2。

  2. std::launder的正确使用方式

  • 适用场景:当在已结束生命周期的对象内存位置上重建同类型(或兼容类型)对象,且原对象满足以下任一条件时,必须使用std::launder:
    • 原对象是const限定类型
    • 原对象包含非静态const成员
    • 原对象是引用类型
  • 使用方法:将指向原对象内存地址的指针传入std::launder,它会返回指向新对象的有效指针。比如示例中的std::launder(&s),即可获取指向新创建S对象的合法指针。
  • 注意事项:不要滥用std::launder,只有符合[basic.life]规定的场景才需要使用,多余的调用不会带来收益,还可能干扰编译器优化。
  1. 该场景的规范是否存在歧义
    C++标准中[basic.life]的相关规则是明确的:const对象的名字在其生命周期结束后,无法自动指代同内存位置上的新对象,必须通过std::launder来建立新对象的合法访问路径。Note 3仅为辅助说明,规范本身的要求清晰,不存在歧义。

内容的提问来源于stack exchange,提问作者Dr. Gut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:10:01