C++ - Copy-and-swap Idiom
I faced an issue implementing BusTub P1 correctly. It’s all about move semantic and resource ownership. I found the “copy-and-swap idiom” very helpful in solving this problem. Here’s a brief explanation of the idiom and how it can be applied in C++.
Motivation
Resource management challenges
When implementing copy/move constructors and assignment operators, we often need to release allocated resources. But this is easy to forget, leading to resource leaks or double frees.
Exception safety
swap(x, y) is usually implemented noexcept, so it won’t throw exceptions. This property helps
ensure that our assignment operators are not leading to resource leaks.
Mechanism
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Widget {
public:
// You should implement these two as usual.
Widget(Widget const& other);
Widget(Widget&& other) noexcept;
Widget& operator=(Widget other) noexcept { // note: pass by value
if (this != &other) swap(*this, other); // swap the contents
return *this;
}
private:
friend void swap(Widget& first, Widget& second) noexcept {
using std::swap;
// swap all members here, e.g.:
// swap(first.member1, second.member1);
// swap(first.member2, second.member2);
}
};
Don’t use operator=(Widget&& other). In this way, destruction of original resource will be
deferred to destruction of outer other, which may not be what you want.
If you want the resource to be cleaned just in time, or you want to disable one of copy and/or move, using seperated implementation for copy/move assignment, you can try the following:
1
2
3
4
5
6
7
8
Widget& operator=(Widget &&other) noexcept { // note: passed by r-value reference.
// When implementing the `Widget const&` version, use `auto tmp = other;`.
if (this != &other) {
auto tmp = std::move(other);
swap(*this, tmp); // swap the contents
}
return *this;
}