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

哪种场景下必须使用std::launder以避免C++未定义行为?

C++20中placement new后是否需要std::launder的场景分析

先看示例代码:

#include <iostream>

struct NonImplicitLifetime{
    NonImplicitLifetime(){}
    ~NonImplicitLifetime(){}
};
int main(){
   // case 1:
   auto ptr = (NonImplicitLifetime*) malloc(sizeof(NonImplicitLifetime)*2); // #1
   auto second = ptr+1;
   new (second) NonImplicitLifetime{};
   *second;   // #2

   // case 2:
   unsigned char buff[sizeof(NonImplicitLifetime) * 2]; // #3
   auto ptr_second = buff + sizeof(NonImplicitLifetime); 
   new (ptr_second) NonImplicitLifetime{};
   *(NonImplicitLifetime*)ptr_second; // #4
}

Case 1 分析

在C++20中,malloc分配的内存会隐式创建包含2个NonImplicitLifetime对象的数组,second指向该数组的第二个元素。当通过placement new在该位置创建新对象时,完全符合[intro.object]第2款的规则:

如果在与成员子对象或数组元素e(可能处于生命周期内,也可能不处于)关联的存储中创建对象,当满足以下条件时,新创建的对象是e所属对象的子对象:

  • e所属对象的生命周期已开始且未结束,
  • 新对象的存储与e关联的存储位置完全重叠,
  • 新对象与e的类型相同(忽略cv限定符)。

此时新对象是原数组的子对象,second会自动指向新创建的对象,不需要使用std::launder,#2处的解引用操作是合法的。

Case 2 分析

unsigned char buff[]是unsigned char类型的数组,其元素类型与NonImplicitLifetime完全不同。当在ptr_second指向的存储位置(对应原数组的某个unsigned char元素)创建NonImplicitLifetime对象时,不满足[intro.object]第2款的“类型相同”条件,因此新对象不是原数组的子对象——原数组仅提供存储空间(依据[intro.object]第3款)。

此时(NonImplicitLifetime*)ptr_second这个指针仍然关联着生命周期已结束的unsigned char元素,而非新创建的NonImplicitLifetime对象。直接解引用这个指针属于未定义行为,必须使用std::launder来获取指向新对象的有效指针,修正指针的类型关联后才能合法访问。

内容的提问来源于stack exchange,提问作者xmh0511

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:03:38