我创建了一个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;
}
答案 0 :(得分:1)
当必须允许传递空指针时,建议使用原始指针-在您的示例中不为true;或必须传递非整数值时(在您的情况下为true)。在后一种情况下,仍应考虑传递引用而不是原始指针。这是一般性建议-因此可能存在例外。
请注意,您仍然可以在这里安全地在函数中使用原始指针,方法是将find_node(...)设为私有函数,同时将insert(...)公开。这是安全的,因为没有机会使指针从insert(...)内部悬空。
本质上,我们需要使用原始指针来防范两种可能性:#1。过早删除指针指向的内存,即#2。永远不要删除指针指向的内存。在insert(...)函数内部,这两种方法均不可行。所以你很安全。
在相关说明中,如果要由多个子节点共享它们,则可以考虑在创建节点时为它们使用unique_pointer,然后将其转换为共享指针:std :: move(...)。 / p>