10

Here's a very easy way to define move assignment for most any class with a move constructor:

class Foo {
public:
  Foo(Foo&& foo);                     // you still have to write this one
  Foo& operator=(Foo&& foo) {
    if (this != &foo) {               // avoid destructing the only copy
      this->~Foo();                   // call your own destructor
      new (this) Foo(std::move(foo)); // call move constructor via placement new
    }
    return *this;
  }
  // ...
};

Is this sequence of calling your own destructor followed by placement new on the this pointer safe in standard C++11?

2
  • 2
    Your move constructor had better be noexcept, or you'll attempt destroy an already-destroyed object if it throws and wander off in UB-land. Commented Oct 26, 2012 at 19:40
  • 1
    A good trick for move/copy assignment is to simply take the parameter by value. A user will either move-construct the value parameter or copy-construct it (or elide into it). You can then use std::swap to swap the value into your object. Commented Oct 27, 2012 at 0:10

2 Answers 2

5

Only if you never, ever derive a type from this class. If you do, this will turn the object into a monstrosity. It's unfortunate that the standard uses this as an example in explaining object lifetimes. It's a really bad thing to do in real-world code.

Sign up to request clarification or add additional context in comments.

11 Comments

Is there also a problem with taking new-allocated memory, manually ~dtoring it, then placement newing it? I'd have to standard-delve to check that this is permitted myself.
@Yakk no, since you're not [de]allocating anything.
@Yakk no, there should be no problem in that respect so long as the object you originally allocated has size and alignment requirements sufficient for the object you create via placement new, and the pointer you pass to delete is of an appropriate type.
If the derived class has a virtual destructor or needs to do something special for move assignment, shouldn't the move assignment be virtual and also overridden in the sub-class? In that case the derived class can just implement move assignment in the same way. If the derived class author doesn't know not to call the super-class move-assignment then there is a problem, yes - it's either this way all the way or not at all. Is this specifically your concern?
@InnocentBystander — add a virtual function, and override it in a derived class. Now (too much implementation detail here) the constructor call in that assignment operator will replace the derived type’s vtable pointer with the base type’s vtable pointer. Voila, object of derived type but virtual calls don’t go to their overriders.
|
0

Technically, the source code is safe in this tiny example. But the reality is that if you ever even look at Foo funny, you will invoke UB. It's so hideously unsafe that it's completely not worth it. Just use swap like everybody else- there's a reason for it and it's because that's the right choice. Also, self-assignment-checking is bad.

2 Comments

Copy and swap is not always the best implementation. It's one easy way of getting the strong exception safety guarantee, but there are trade-offs. Howard Hinnant discusses it some in part of this answer.
Is your concern mainly with a derived class author (erroneously in this case) calling the Foo move assignment, or are there more problems than that? This technique does require sub-class authors to override virtually and use the technique too. Most problems I can think of beyond that involve the move assignment not being virtual and then the answer just is that the move assignment should be virtual in those cases regardless of whether this technique is used (do you agree?). Do you have concerns beyond that?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.