【发布时间】:2018-08-01 23:25:14
【问题描述】:
我创建了一个Node 结构,用于实现二叉搜索树。它使用共享指针来跟踪其子代:
template <class T> struct Node;
template <class T>
using Node_ptr = std::shared_ptr<Node<T>>;
template <class T>
struct Node {
Node_ptr<T> left;
Node_ptr<T> right;
const T label;
...
};
现在,我想要一个函数,它给出一些子树,一个值将返回该特定值的节点或该节点将来应该位于的位置 - find_node。
现在是这样的:
template <class T>
auto* find_node(Node_ptr<T>* node, const T& value) {
for (; *node && (*node)->label != value
; node = value < (*node)->label ? &(*node)->left : &(*node)->right);
return node;
}
相当糟糕。但它有效:
template <class T>
class Binary_search_tree {
public:
// correctly inserts consecutive values
void insert(const T& value) {
if (auto* node = find_node(&root, value); !*node)
*node = std::make_shared<Node<T>>(value);
}
...
private:
Node_ptr<T> root;
...
};
我可以重写find_node 以使用std::shared_ptr<Node_ptr<T>> 而不是Node_ptr<T>*,但它看起来会更糟。还是会?
我应该如何处理这种情况?
编辑:正如已经指出的那样,可以通过引用起始节点并返回对节点的引用来简化函数:
template <class T>
Node_ptr<T>& find_node(Node_ptr<T>& node_ref, const T& value) {
auto* node = &node_ref;
...
return *node;
}
【问题讨论】:
-
由于您没有直接分配
Node_ptr<T> *,您所做的可能看起来“很糟糕”,但它也有效,我认为没有理由包装共享在这种情况下,共享指针周围的指针。如果您一直在分配和存储指向共享指针的指针,那将会改变事情。综上所述,您有什么理由不使用 reference 返回类型?在您提出的情况下,我认为node永远不会为NULL。事实上,通过的node也将是参考候选。 -
你真的需要
shared_ptr吗?您是否在不同的树或其他东西之间共享节点? -
@WhozCraig 谢谢!实际上,起始节点和返回的节点都可以通过引用传递。我完全忽略了这个事实,更关注函数体。但正如您所指出的,在使用原始指针的方式中,它们通常不会带来与它们相关的风险。也许我只是挖得太深了:)
-
如果您不在树之间共享注释或允许将一个相同的节点多次插入到一棵树中,那么您只能在一种情况下(节点删除)从智能指针中受益,而在所有其他情况下(插入、移动节点,例如用于树平衡,...),您将有相当多的开销,因为除了修改树之外,您实际上不会共享指针(无论如何,所有涉及的节点都是已知的... )。那么也许
std::unique_ptr是一个更好的选择?
标签: c++ shared-ptr c++17 smart-pointers