C++23是否保证在placement new场景中可省略std::launder?
C++23中placement new覆盖const对象后,是否无需std::launder即可访问成员?
示例代码
#include <iostream> #include <new> struct A { int const n; void f() { new (this) A{2}; } void g() { std::cout << this->n; } void h() { std::cout << std::launder(this)->n; } }; int main() { auto a = A{1}; a.f(); std::cout << std::launder(&a)->n; // 此语句保证输出2 a.h(); // 此语句保证输出2 a.g(); // 是否保证输出2? std::cout << a.n; // 是否保证输出2? new (&a) A{3}; std::cout << std::launder(&a)->n; // 此语句保证输出3 a.h(); // 此语句保证输出3 a.g(); // 是否保证输出3? std::cout << a.n; // 是否保证输出3? }
背景说明
编译器可以假设真正的const变量(不仅是const&,而是声明为const的对象变量)永远不会改变。
std::cout << std::launder(&a)->n;的行为符合预期是有保证的,但该写法繁琐且不美观,尤其在成员函数体内的this指针场景中。
问题
C++23是否保证即使不使用std::launder,std::cout << a.n;和std::cout << this->n;的行为也符合预期?
回答
C++23确实放宽了相关规则,针对通过placement new在原有存储位置合法构造新对象覆盖const对象的场景,无需std::launder即可保证访问行为符合预期:
- 对于直接通过对象名访问成员(如
a.n):当a的存储位置被placement new创建的新A对象覆盖后,C++23标准保证后续对a.n的访问会指向新对象的n成员,编译器不能再因n是const成员而缓存旧值。 - 对于成员函数中
this->n的访问:当this指向的对象被placement new重新构造后,C++23允许直接通过this->n访问新对象的成员,无需调用std::launder(this)。
需要注意的是,这种规则放宽的前提是必须合法地在原有对象的存储位置构造了新对象,如果没有完成合法的新对象构造,访问const成员的行为依然属于未定义行为。
内容的提问来源于stack exchange,提问作者xmllmx
相关产品推荐
相关产品推荐

