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

C++中通过基类重新构造对象的行为是否符合标准明确定义?

代码行为分析结论

你提供的代码包含未定义行为,仅动态内存分配场景的行为是明确定义的,各场景具体分析如下:

规则背景

你提到的C++标准6.7.3第9款的规定准确,该条款约束的是自动存储期对象(栈对象)隐式调用析构函数的场景:

当隐式析构函数调用发生时,若原类型的另一个对象并未占用该存储位置,则程序行为是未定义的


各场景逐一分析

1. 未调用method的右值引用场景

{
    type&& obj = method_called{};
    std::cout << "\ndestr~" << __FUNCTION__ << "\n" << std::endl;
}

该场景行为明确定义:右值引用延长了临时method_called对象的生命周期,作用域结束时会正确调用派生类method_called的析构函数,无任何问题。

2. 栈临时对象调用method的场景

{
    type&& obj = method_called{};
    obj.method();
    std::cout << "\ndestr~" << __FUNCTION__ << "\n" << std::endl;
}

该场景触发未定义行为:

  • 调用obj.method()时,因为析构函数是虚函数,this->~type()实际会调用完整的method_called::~method_called(),将原派生类对象完全析构
  • 后续placement new操作在原存储位置构造了一个基类type对象,和原临时对象的method_called类型不一致
  • 作用域结束触发隐式析构时,编译器默认该位置还是method_called类型的对象,会尝试调用method_called的析构函数,此时存储位置实际是type对象,完全符合6.7.3第9款描述的未定义行为场景,输出结果不可靠。

3. 动态内存分配场景

method_called* pobj = new method_called{};
pobj->method();
std::cout << "\ndestr~" << __FUNCTION__ << "\n" << std::endl;
delete pobj;

该场景行为明确定义:

  • 6.7.3第9款仅约束自动存储期对象的隐式析构,动态分配的对象不存在自动触发析构的逻辑,不受该条款约束
  • 调用method完成析构和重构造后,pobj指向的存储位置是一个合法的type对象,type和method_called的析构函数都是虚函数,delete pobj时会调用当前存储对象的实际析构函数type::~type(),流程完全符合标准规定。

补充说明

你在method内先调用析构函数、再用placement new原地构造对象的操作本身是合法的,只要保证后续对该内存的使用符合对象生命周期规则即可,仅栈对象场景因为隐式析构的类型不匹配才会出现未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 09:51:00