我正在为一个二叉搜索树类实现一个 insert
函数,这个函数有两个版本,一个是用左值项(要插入到树中的项)调用的,另一个是一个在我使用 std::move
的地方有一个右值。
第一个:
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);
}
第二个:
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?
}
第二个函数中insert
的递归调用应该用x
调用还是用std::move(x)
调用?
我的猜测是它应该是 x
因为它已经是一个右值并且不需要 move()
,但是,我使用的指南实现使用了 std::move()
最佳答案
首先,考虑标准对那些可以 move 的对象的规定:
[...] moved-from objects shall be placed in a valid but unspecified state.
你不能期望它也适用于所有用户定义的类型,但它是一种常见模式。
我们假设 Comparable
就是这种情况并分析你的第二个函数:
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?
}
如果t
等于 nullptr
,你动x
在t
.
在该操作之后,可能会发生 x
处于有效但未指定的状态。
这意味着 x < t->element
以及x > t->element
有未定义的行为。
换句话说,一旦您将对象移出,您就不应该再使用它。同样,您不应 move 同一对象两次。
Should the recursive call of insert in the second function be called with x or std::move(x)?
你可以简单地重写如下:
template <typename Comparable>
void BinarySearchTree<Comparable>::insert(Comparable &&x, BinaryNode* &t)
{
if (t == nullptr) {
t = new BinaryNode(std::move(x), nullptr, nullptr);
} else if (x < t->element) {
insert(std::move(x), t->left);
} else if (x > t->element) {
insert(std::move(x), t->right);
}
}
move Comparable
只有一次。
关于c++ - 右值的函数重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41200827/