在指向指针方案的指针中使用std :: shared_ptr

时间:2018-08-01 23:25:15

标签: c++ shared-ptr c++17 smart-pointers

我创建了一个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;
}

1 个答案:

答案 0 :(得分:1)

  1. 当必须允许传递空指针时,建议使用原始指针-在您的示例中不为true;或必须传递非整数值时(在您的情况下为true)。在后一种情况下,仍应考虑传递引用而不是原始指针。这是一般性建议-因此可能存在例外。

  2. 请注意,您仍然可以在这里安全地在函数中使用原始指针,方法是将find_node(...)设为私有函数,同时将insert(...)公开。这是安全的,因为没有机会使指针从insert(...)内部悬空。

本质上,我们需要使用原始指针来防范两种可能性:#1。过早删除指针指向的内存,即#2。永远不要删除指针指向的内存。在insert(...)函数内部,这两种方法均不可行。所以你很安全。

在相关说明中,如果要由多个子节点共享它们,则可以考虑在创建节点时为它们使用unique_pointer,然后将其转换为共享指针:std :: move(...)。 / p>