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

C++中多次透明替换对象后复用原指针是否符合标准?

C++对象多次透明替换后复用原指针的合法性问题

根据C++标准,对象可被透明替换。但标准是否允许对象被多次替换后仍复用原指针?

具体而言,如下示例中第二次调用new (this) C(other)是否仍符合标准中的如下条款:

若某对象生存期结束后,且在其占用的存储被复用或释放前,在该存储位置创建新对象,则指向原对象的指针、引用或原对象的名称将自动指代新对象,且新对象生存期开始后可用于操作新对象——前提是原对象可被新对象透明替换。

示例代码

struct C {
  int i;
  void f();
  const C& operator=( const C& );
};

const C& C::operator=( const C& other) {
  if ( this != &other ) {
    this->~C();                 // *this 的生存期结束
    new (this) C(other);        // 创建新的C对象(存储已被复用?)
    new (this) C(other);        // 再次创建新的C对象(存储再次被复用?)!
    f();                        // 这里是否仍定义良好?
  }
  return *this;
}

C c1;
C c2;
c1 = c2;                        // 这里是否仍定义良好?

核心疑问

从技术层面看,第二次调用new (this) C(other)时,新对象被创建,存储位置被复用,随后原(前一个)对象的生存期才结束?这是否不符合标准条款,导致上述代码出现未定义行为(UB)?因为标准明确要求存储复用前原对象生存期已结束,而此处似乎是先复用存储再结束生存期?


结论:代码存在未定义行为

关键分析点

  1. 第一次替换的合法性:
    第一次调用this->~C()结束了原对象的生存期,随后new (this) C(other)在同一块存储上创建新对象,完全符合标准条款的要求——此时this指针自动指代新创建的对象,这一步是合法的。

  2. 第二次替换的问题:
    第二次调用new (this) C(other)时,当前存储上已经存在一个处于生存期内的C对象。根据C++标准,在一个对象的生存期尚未结束时,复用其存储位置创建新对象的行为是未定义的。
    标准条款的前提是“原对象生存期结束后”才能复用存储创建新对象,而第二次placement new操作时,前一个由第一次placement new创建的对象还在生存期内(我们并没有显式调用它的析构函数),因此直接复用存储创建新对象违反了标准要求,触发未定义行为。

  3. 后续操作的影响:
    一旦触发未定义行为,后续的f()调用以及return *this的行为都不再有定义——程序可能崩溃、输出异常结果,或表现出任何不可预测的行为。

修正建议

如果需要多次替换对象,必须确保每次创建新对象前,先结束当前对象的生存期:

const C& C::operator=( const C& other) {
  if ( this != &other ) {
    this->~C();                 // 结束原对象生存期
    new (this) C(other);        // 第一次创建新对象
    this->~C();                 // 结束第一个新对象的生存期
    new (this) C(other);        // 第二次创建新对象,此时存储复用前对象生存期已结束
    f();                        // 此时合法,this指代最新的对象
  }
  return *this;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:33:30