 
                            ...
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #include <new>
#include <utility>
 
struct S { /* ... */ }; // Has nonthrowing copy constructor
 
class T {
  int n;
  S *s1;
 
public:
  T(const T &rhs) : n(rhs.n), s1(rhs.s1 ? new S(*rhs.s1) : nullptr) {}
  ~T() { delete s1; }
  // ...
 
  void swap(T &rhs) noexcept {
    using std::swap;
    swap(n, rhs.n);
    swap(s1, rhs.s1);
  }
 
  T& operator=(const T &rhs) noexcept {
    T(rhs).swap(*this);
    return *this;
  }
}; | 
Compliant Solution (Move and Swap)
This compliant solution uses the same classes S and T from the previous compliant solution, but adds the following public constructor and methods:
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
|   T(T &&rhs) { *this = std::move(rhs); }
  // ... everything except operator= ..
  T& operator=(T &&rhs) noexcept {
    using std::swap;
    swap(n, rhs.n);
    swap(s1, rhs.s1);
    return *this;
  }
  T& operator=(const T &rhs) noexcept {
    T temp(rhs);
    *this = std::move(temp);
    return *this;
  } | 
The copy assignment operator uses std::move() rather than swap() to achieve safe self-assignment and a strong exception guarantee. The move assignment operator uses a move (via the method parameter) and swap. Note that unlike a copy assignment, a move assignment is allowed to modify the values of rhs.
Risk Assessment
Allowing a copy assignment operator to corrupt an object could lead to undefined behavior.
...