有时候我想与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来实现与副本构造具有相同语义的副本分配?
答案 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)
有什么真正的大理由为什么不应该这样做?
您必须绝对确保每个派生类都定义自己的赋值运算符,即使它是微不足道的。因为派生类的隐式定义的副本分配运算符会将所有内容弄乱。它将调用S::operator=
,它将在其位置重新创建错误类型的对象。
此类破坏和构造赋值运算符不能被任何派生类重用。因此,不仅要强迫派生类提供显式的复制运算符,而且要迫使它们在其赋值运算符中遵循相同的销毁和构造习惯。
您必须绝对确保在由这样的赋值运算符破坏和构造对象时,没有其他线程正在访问该对象。
一个班级可能有一些数据成员,它们不能受赋值运算符的影响。例如,线程安全类可能具有某种互斥量或关键部分成员,而当当前线程将要破坏并构造该互斥量时,其他一些线程正等待着它们。
在性能方面,与标准的复制和交换习惯相比,它实际上没有优势。那么,克服上述所有痛苦有什么好处?