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

C++17中在单次内存分配内合法构造对象的方法问询

在同一块内存分配中存储不同类型对象的合法性分析

原问题代码

#include<cstdlib>
#include<new>

struct A {
  int a;
  int b;
};

struct B {
  int c;
};

int main() {
  void* storage = std::malloc(1024);
  char* ptr = reinterpret_cast<char*>(storage);
  ptr += 16;
  new(ptr) A;
  ptr += sizeof(A);
  // construct other objects in the same way
  new(ptr) B;
}

代码合法性分析

根据已被采纳且具有追溯效力的P0593提案,reinterpret_cast<char*>(storage)会隐式创建一个char数组,因此初始的指针运算ptr += 16是定义良好的。

但执行new(ptr) A时,会覆盖ptr到ptr + sizeof(A) - 1范围内的内存,结束该范围内隐式创建的char元素的生命周期。此时ptr指向的是已结束生命周期的对象,后续的ptr += sizeof(A)属于未定义行为(UB)。

基于此,相关问题的答案中存在UB,因为其在placement new后执行了指针递增操作。

可行解决方案

1. 使用std::launder(仍存在风险)

new(ptr) A;
// std::launder(ptr)以char*指向已构造的A实例,char指针可别名任何对象
ptr = std::launder(ptr) + sizeof(A); 
// ptr += 16; // 仍为UB

这种方式仍可能存在UB:std::launder(ptr)指向的是A对象而非数组对象,对非数组对象进行指针运算属于非法操作,例如后续执行ptr += 128仍为UB。

2. 先递增指针再执行placement new(推荐)

ptr += sizeof(A); // 预先将指针移至A对象之后的位置
new(ptr - sizeof(A)) A;
// ptr始终指向隐式创建的char数组中存活的元素,后续指针运算合法

通过预先移动指针,避免ptr指向已销毁的对象,确保后续所有指针操作都基于存活的char数组元素,完全符合标准定义。

3. 先构造对象再用std::memcpy复制(简单可靠)

先在栈或其他内存区域构造对象,再通过std::memcpy将对象内容复制到目标内存区域。这种方式逻辑简单,完全符合标准,不存在UB风险。

结论

方案2和方案3是定义良好的可行解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:40:14