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

C++20/23标准中重复析构与未析构复用存储的合规性问询

现代C++(C20/C23)中placement new与显式析构的违规操作及标准依据

1. 重复调用析构函数

alignas(T) std::byte storage[sizeof(T)];
T* const p = new (storage) T(...);
p->~T();
p->~T();

在C20及C23标准中,无论T的析构函数是否平凡,上述代码均属于未定义行为。

标准条款依据

根据C20/C23标准的[class.dtor]/11条款:

一旦对象的析构函数被调用,该对象即不再存在;若对生命周期已结束的对象调用析构函数,行为是未定义的。[注:即使对象的析构函数是平凡的,此规则依然适用,因为析构函数的调用会销毁对象。——结束注]

C20修改了C17中对平凡析构函数重复调用的宽松规则,明确将其纳入未定义行为范畴:即使平凡析构不执行任何实际操作,调用析构函数的动作本身会标记对象生命周期的结束,后续对该“已销毁对象”的操作不再合法。

2. 未调用析构函数就复用存储

alignas(T) std::byte storage[sizeof(T)];
T* p = new (storage) T(...);
p = new (storage) T(...);
p->~T();

当T的析构函数非平凡时,上述代码属于未定义行为;若T的析构函数平凡,则该操作是允许的。

标准条款依据

根据C20/C23标准的[basic.life]/14条款:

若对象o的生命周期已结束,且其占用的存储被复用或释放,程序必须确保o的析构函数被调用,除非满足以下任一条件:

  1. 对象是联合体的非当前成员;
  2. 对象的析构函数是平凡的;
  3. 对象类型为T,且在o占用的存储中创建了一个T类型(或T的派生类型)的新对象,且T的析构函数是平凡的。

对于非平凡析构的T,直接在已有对象的存储上调用placement new创建新对象,会结束旧对象的生命周期,但未调用其析构函数,违反了上述条款的要求,因此行为未定义。而平凡析构的T满足例外条件,无需显式调用旧对象的析构函数即可复用存储。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 11:37:04