简体   繁体   English

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

[英]Is using a placement new as a copy assignment operator bad?

Sometimes I want to make classes/structs with const members. 有时我想使用const成员来制作类/结构。 I realize that this is a bad idea for multiple reasons, but for the sake of argument let's pretend the only reason is that it makes a well-formed operator = a hassle, to say the least. 我意识到这是一个坏主意,有多种原因,但是为了争辩,让我们假装唯一的原因是,至少可以说,它使格式正确的operator =麻烦。 However, I contrived a fairly simple work-around to it, as demonstrated by this struct: 但是,我构造了一个相当简单的解决方法,如以下结构所示:

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;
  }

};

Ignoring destructors and move semantics, is there any really big reason why this shouldn't be done? 忽略析构函数并移动语义,有什么真正的大理由为什么不应该这样做? It seems to me like a more type-safe version of 在我看来,它更像是类型安全的

S& operator =(const S& other) {
  const_cast<int&>(i) = other.i;
  return *this;
}

So, the summary of the question is this: is there any major reason placement-new should not be used to implement copy assignment to have the same semantics as a copy construction? 因此,问题的摘要是:是否有任何主要理由不应该将placement-new用于实现与副本构造具有相同语义的副本分配?

I don't believe that placement new is a problem here but the const_cast which produces undefined behavior: 我认为这里的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. C ++ 10.1.7.1-4除了可以声明任何声明为可变的类成员(10.1.1)之外,任何在其生存期内(6.6.3)修改const对象的尝试都会导致未定义的行为。

You'll probably get away with this until compiler starts to optimize things. 在编译器开始优化之前,您可能会避免这样做。

The other problem is the use of a placement new on a piece memory occupied by living (non-destroyed) object. 另一个问题是在由活动(未破坏)对象占用的内存中使用新的放置方式。 But you'll probably get away with this while object in question has a trivial destructor. 但是,当有问题的对象具有微不足道的析构函数时,您可能会摆脱这种情况。

is there any really big reason why this shouldn't be done? 有什么真正的大理由为什么不应该这样做?

  1. You must be absolutely sure that every derived class defines its own assignment operator, even if it is trivial. 您必须绝对确保每个派生类都定义自己的赋值运算符,即使它是微不足道的。 Because an implicitly defined copy-assignment operator of a derived class will screw everything. 因为派生类隐式定义的副本分配运算符会将所有内容搞混。 It'll call S::operator= which will re-create a wrong type of object in its place. 它将调用S::operator= ,它将在其位置重新创建错误的对象类型

  2. Such destroy-and-construct assignment operator can't be re-used by any derived class . 这样的销毁构造赋值运算符不能被任何派生类重用 So, not only you are forcing derived classes to provide an explicit copy operator, but you're forcing them to stick to the same destroy-and-construct idiom in their assignment operator. 因此,不仅要强迫派生类提供一个显式的复制运算符,而且要迫使它们在其赋值运算符中遵循相同的销毁和构造习惯。

  3. You must be absolutely sure that no other thread is accessing the object while it is being destroyed-and-constructed by such assignment operator. 您必须绝对确保在这样的赋值运算符破坏和构造对象时,没有其他线程可以访问该对象

  4. A class may have some data members that must not be affected by the assignment operator . 一个类可能包含一些数据成员,这些成员不能受到赋值运算符的影响 For example, a thread-safe class may have some kind of mutex or critical section member, with some other thread waiting on them right when the current thread is going to destroy-and-construct that mutex... 例如,一个线程安全的类可能具有某种互斥量或关键部分成员,当当前线程将要破坏并构造该互斥量时,其他一些线程将在其上等待...

  5. Performance-wise, it has virtually no advantage over standard copy-and-swap idiom. 在性能方面,它几乎没有标准的复制和交换习惯的优势。 So what would be the gain in going through all the pain mentioned above? 那么,克服上述所有痛苦将有何收获?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM