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:
- Make a copy of
b's data. - Release
a's old data. - Handle self-assignment (
a = a;), which a naive version breaks by freeing the data before copying it. - Ideally, leave
aunchanged 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
- The parameter
otheris already a fresh copy. If copying fails, it fails before anything in*thischanged. swapgives*thisthe new data and givesotherthe old data.- When
operator=returns,othergoes out of scope and its destructor frees the old data. No explicitdeleteneeded. - Self-assignment is safe automatically: you copy first, then swap.
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=.