使用 placement new 作为复制赋值运算符不好吗?

Is using a placement new as a copy assignment operator bad?

有时我想与 const 成员建立 classes/structs。我意识到出于多种原因这是一个坏主意,但为了争论起见,让我们假装唯一的原因是至少可以说它使格式良好的 operator = 变得麻烦。但是,我设计了一个相当简单的解决方法,如以下结构所示:

struct S {

  const int i;

  S(int i) : i(i) {}

  S(const S& other) : i(other.i) {}

  S& operator =(const S& other) {
    new (this) S(other);
    return *this;
  }

};

忽略析构函数和移动语义,有什么不应该这样做的真正重要原因吗?在我看来,它更像是

的类型安全版本
S& operator =(const S& other) {
  const_cast<int&>(i) = other.i;
  return *this;
}

所以,问题的总结是这样的:是否有任何主要原因不应该使用 placement-new 来实现复制赋值以具有与复制构造相同的语义?

我认为 placement new 在这里不是问题,但是 const_cast 会产生未定义的行为:

C++ 10.1.7.1-4 Except that any class member declared mutable (10.1.1) can be modified, any attempt to modify a const object during its lifetime (6.6.3) results in undefined behavior.

在编译器开始优化之前,您可能不会遇到这种情况。

另一个问题是在被活动 (non-destroyed) 对象占用的一块内存上使用了新的放置。但是当有问题的对象有一个微不足道的析构函数时,你可能会摆脱这个。

is there any really big reason why this shouldn't be done?

  1. 您必须绝对确定每个派生的 class 都定义了自己的赋值运算符,即使它是微不足道的。因为派生的 class 的 隐式定义 copy-assignment 运算符会搞砸 一切。它将调用 S::operator=,这将 re-create 错误类型的对象 取而代之。

  2. 这样的 destroy-and-construct 赋值运算符 不能被任何派生的 class re-used。因此,您不仅强迫派生的 classes 提供显式复制运算符,而且还强迫它们在赋值运算符中坚持使用相同的 destroy-and-construct 习语。

  3. 您必须绝对确定没有其他线程正在访问该对象,而它正被这样的赋值运算符destroyed-and-constructed访问。

  4. A class 可能有一些数据 成员不能受赋值运算符 的影响。例如,thread-safe class 可能有某种互斥体或关键部分成员,当当前线程要 destroy-and-construct 那个互斥体时,其他线程正在等待它们...

  5. Performance-wise,与标准的 copy-and-swap 成语相比,它实际上 没有优势 。那么,经历了上述所有的痛苦,会有什么收获呢?