C/C++ Arena

Step 6 of 8

Copy assignment with copy-and-swap

Copy assignment (a = b; where a already exists) is trickier than the copy constructor, because a already owns a resource. A correct version must:

  1. Make a copy of b's data.
  2. Release a's old data.
  3. Handle self-assignment (a = a;), which a naive version breaks by freeing the data before copying it.
  4. Ideally, leave a unchanged if making the copy fails.

The classic solution is copy-and-swap. Take the parameter by value (so the compiler makes the copy using your copy constructor), then swap your members with the copy's:

#include <iostream>
#include <utility>

class Box {
public:
    explicit Box(int v) : p_(new int(v)) {}
    Box(const Box& o) : p_(new int(*o.p_)) {}
    ~Box() { delete p_; }
    void swap(Box& o) noexcept { std::swap(p_, o.p_); }
    Box& operator=(Box other) {
        swap(other);
        return *this;
    }
    int get() const { return *p_; }

private:
    int* p_;
};

int main() {
    Box a(1), b(2);
    a = b;
    a = a;
    Box c(3);
    c = a;
    std::cout << a.get() << " " << b.get() << " " << c.get() << "\n";
}
2 2 2

Why it works

operator= returns *this by reference, so assignments can chain (a = b = c). The swap member is marked noexcept because swapping two pointers can't fail, and the standard library relies on that promise.

Your turn: write the member swap and the copy-and-swap operator=.

Previous: Non-copyable classes Next: The rule of zero