I am implementing an insert function for a binary search tree class, there are two versions for the function, one that is called with an lvalue item (the item to be inserted to the tree) and one with an rvalue where I am using std::move.
The first:
template <typename Comparable>
void BinarySearchTree<Comparable>::insert(const Comparable &x, BinaryNode* &t)
{
if (t == nullptr)
t = new BinaryNode(x, nullptr, nullptr);
if (x < t->element)
insert(x, t->left);
if (x > t->element)
insert(x, t->right);
}
The second:
template <typename Comparable>
void BinarySearchTree<Comparable>::insert(Comparable &&x, BinaryNode* &t)
{
if (t == nullptr)
t = new BinaryNode(std::move(x), nullptr, nullptr);
if (x < t->element)
insert(x, t->left); // should this be insert(std::move(x), t->left)?
if (x > t->element)
insert(x, t->right); // also here?
}
Should the recursive call of insert in the second function be called with x or std::move(x)?
My guess is that it should be x as it's already an rvalue and no need for move(), however, the guide implementation I am using used std::move()
First of all, consider what the standard says for those objects that can be moved:
You cannot expect that it applies also to all the user defined types, but it's a common pattern.
Let's suppose it's the case for a
Comparableand analyze your second function:If
tequals tonullptr, you movexint.After that operation, it could happen that
xis in a valid but unspecified state.It means that
x < t->elementas well asx > t->elementhave an undefined behavior.In other terms, you should not use an object once you have moved it out. Similarly, you should not move twice the same object.
You can simply rewrite it as it follows:
Move a
Comparableonly once.