When I write classes that hold resources, I'm very accustomed to writing simple swap functions to simplify the process of transferring/copying resources. The following code is a trivial example:
class MyArray {
public:
MyArray(size_t size) :
_array(size ? new int[size] : nullptr),
_size(size)
{
}
MyArray(const MyArray & mv) :
MyArray(mv._size)
{
if(mv._size) std::copy(mv._array, mv._array + mv._size, _array);
}
static void friend swap(MyArray & mv1, MyArray & mv2) noexcept {
std::swap(mv1._array, mv2._array);
std::swap(mv1._size, mv2._size);
}
MyArray(MyArray && mv) {
swap(*this, mv);
}
MyArray & operator=(MyArray mv) {
swap(*this, mv);
return *this;
}
~MyArray() noexcept {
delete[] _array;
}
int & operator[](size_t index) {
if(index >= _size) throw std::exception("Index Out of Bounds!");
return _array[index];
}
const int & operator[](size_t index) const {
if(index >= _size) throw std::exception("Index Out of Bounds!");
return _array[index];
}
size_t size() const {
return _size;
}
private:
int * _array;
size_t _size;
};
However, I could have chosen to [equivalently] implement the same code like so:
class MyArray {
public:
MyArray(size_t size) :
_array(size)
{
}
int & operator[](size_t size) {
if(index >= size()) throw std::exception("Index Out of Bounds!");
return _array[index];
}
const int & operator[](size_t index) const {
if(index >= size()) throw std::exception("Index Out of Bounds!");
return _array[index];
}
size_t size() const {
return _array.size();
}
private:
std::vector<int> _array;
};
And in the second code, the swap
functionality defaults to the normal std::swap
behavior (i.e. move-construct the first into the temporary, move-assign the second into the first, and move-assign the temporary into the second), which should be identical (on a design level) to the first code.
The question I have then, is what would be a scenario where I must explicitly define the swap
function, but isn't specifically a scenario where I'm just trying to reuse code (like from the first example code)? Are there obvious (or not-so-obvious) scenarios where, even though nothing in my code is explicitly managing a resource, I will objectively benefit from a swap
function? Should I just auto-write a swap
function for every [move-constructable] class I write, or will I just waste code by doing that?