I have a user-defined class (tree structure) with implemented move semantics, and a swap
function. I would like to implement a move
function the proper way, working as standard std::move implementation.
In the tree node class, each child node has a parent
pointer, pointing to the parent node. This means that for move operations, all children have to reparented (and there may be many children)
This means that use of swap
for moving is not optimal, as children of both lists have to be reparented after being swapped. So I would like to implement a move
function which clears the moved-from tree.
The declaration of std::move implementations is somewhat complicated, they use a std::remove_reference<T>::type&&
return type. Do I need this?
You don't need to write a specialisation of std::move.
If you write a correct move constructor and move assignment operator, std::move will work on your class.
example:
#include <iostream>
#include <cstring>
using namespace std;
struct Thing {
Thing()
: _data(new int[100])
{
cout << "default construct\n";
}
// Copy operator
Thing(const Thing& other)
: _data(new int[100])
{
cout << "copy constructor\n";
memcpy(_data, other._data, sizeof(int) * 100);
}
// Move constructor
Thing(Thing&& other) noexcept
: _data(other._data)
{
cout << "move constructor\n";
other._data = nullptr;
}
// assignment operator
Thing& operator=(const Thing& rhs) {
cout << "copy operator\n";
if (&rhs != this) {
Thing tmp(rhs);
std::swap(*this, tmp);
}
return *this;
}
// move assignment operator
Thing& operator=(Thing&& rhs) noexcept {
cout << "move operator\n";
std::swap(_data, rhs._data);
return *this;
}
// destructor necessary since we are working in dangerous new/delete territory
~Thing() noexcept {
cout << "destructor " << (_data ? "object has data" : "object is empty") << "\n";
delete[] _data;
}
private:
int* _data;
};
int main()
{
cout << "constructing a\n";
Thing a;
cout << "constructing b with copy of a\n";
Thing b(a);
cout << "moving a to newly constructed c\n";
Thing c(std::move(a));
cout << "moving c back to a\n";
a = std::move(c);
cout << "create a new d\n";
Thing d;
cout << "replace d with a copy of a\n";
d = a;
return 0;
}
Program's output:
constructing a
default construct
constructing b with copy of a
copy constructor
moving a to newly constructed c
move constructor
moving c back to a
move operator
create a new d
default construct
replace d with a copy of a
copy operator
copy constructor
move constructor
move operator
move operator
destructor object is empty
destructor object has data
destructor object has data
destructor object is empty
destructor object has data
destructor object has data
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With