将新的展示位置用作副本分配运算符是否不好?

时间:2019-07-12 15:52:29

标签: c++ assignment-operator placement-new

有时候我想与const成员一起创建类/结构。我意识到这是一个不好的主意,有多种原因,但是为了争辩,让我们假装唯一的原因是,至少可以说,它使格式良好的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来实现与副本构造具有相同语义的副本分配?

2 个答案:

答案 0 :(得分:4)

我不认为在这里重新放置是个问题,但是<!DOCTYPE html > <html> <body> <!-- <img> insert logo here --> <header> <nav class="navigation"> <ul> <li class=dropdown> <a href="cat1.html" class="dropdown-head">Catagory1</a> <div class="dropdown-content"> <a href="cont1.html" class="content1">content1</a> <a href="cont2.html">content2</a> <a href="content3.html">content3</a> </div> </li> <li class="dropdown"> <a href="cat2.html">Catagory2</a> <div class="dropdown-content"> <a href="content4.html">content4</a> <a href="content5.html">content5</a> </div> </li> <li><a href="cat3">Catagory3</a></li> </ul> </nav> </header> <div id="main"> <div class="row"> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> </div> <div class="row"> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> </div> <div class="row"> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> <div class="column"> <a href="cont8.html" class="tile"> <div class="overlay"></div> <img class="image" src="img.png"> <div class="container"> <h2>Hello World</h2> </div> </a> </div> </div> </div> </div> </body> </html>会产生不确定的行为:

  

C ++ 10.1.7.1-4   除了可以声明任何声明为可变的类成员(10.1.1)之外,任何在其生存期内(6.6.3)修改const对象的尝试都会导致未定义的行为。

在编译器开始优化之前,您可能会避免使用它。

另一个问题是在由活动(未销毁)对象占用的内存中使用新的放置方式。但是,当有问题的对象具有微不足道的析构函数时,您可能会避免这样做。

答案 1 :(得分:1)

  

有什么真正的大理由为什么不应该这样做?

  1. 您必须绝对确保每个派生类都定义自己的赋值运算符,即使它是微不足道的。因为派生类的隐式定义的副本分配运算符会将所有内容弄乱。它将调用S::operator=,它将在其位置重新创建错误类型的对象

  2. 此类破坏和构造赋值运算符不能被任何派生类重用。因此,不仅要强迫派生类提供显式的复制运算符,而且要迫使它们在其赋值运算符中遵循相同的销毁和构造习惯。

  3. 您必须绝对确保在由这样的赋值运算符破坏和构造对象时,没有其他线程正在访问该对象

  4. 一个班级可能有一些数据成员,它们不能受赋值运算符的影响。例如,线程安全类可能具有某种互斥量或关键部分成员,而当当前线程将要破坏并构造该互斥量时,其他一些线程正等待着它们。

  5. 在性能方面,与标准的复制和交换习惯相比,它实际上没有优势。那么,克服上述所有痛苦有什么好处?