我应该对通用二叉搜索树中的根使用哪种类型的指针



这是我的通用二叉搜索树的标题。现在我只是使用原始指针作为树的根。我应该使用哪种指针?有些类型是独特的,共享的,(智能指针)弱的,原始的,等等。

template <typename T>
class BST
{
public:
BST();
BSTNode<T>* Root;
void Insert(BSTNode<T> newNode);
void Delete(T deleteNode);
BSTNode<T>* ReturnNodeSearch();
BSTNode<T>* MinimumValue();
BSTNode<T>* MaximumValue();
bool isEmpty();
};

使用std::unique_ptr,因为您不太可能希望两个单独的BST对象共享相同的实现节点。通常,在这种情况下,您只需使用外部引用或(可能)对BST对象本身的外部std::shared_ptr

这只取决于你想做什么。我建议最佳做法是使用std::unique_ptr<>std::shared_ptr<>来确保在不再需要时正确释放内存。但是,原始指针可以在这里工作,尽管您必须自己处理释放。通常,智能指针用于处理和拥有动态分配的内存的好处往往超过使用原始指针的好处。

更详细但更高级别:

  • 原始指针 - 处理问题,但如果您不再需要此内存,则只需管理释放。当另一个对象仍然有指向它的指针时,您可能会意外地释放一个对象/函数中的内存
  • std::unique_ptr<>-- 将在其生命周期内管理内存,如果您不必与任何其他对象共享指针,那就太好了
  • std::shared_ptr<>-- 还将管理内存,通过引用计算有多少std::shared_ptr<>也在监视内存位置来增加一些开销。这也将确保只有在没有其他std::shared_ptr<>对象指向内存时才删除内存
  • std::weak_ptr<>-- 只能与std::shared_ptr<>结合使用,用于防止内存中同一对象的引用周期

不一定有错误的答案。这仅取决于您所需的实现。您永远不应该使用的唯一类型是std::auto_ptr<>,因此请避免使用该类型。

在查看您的代码示例时,会想到 3 个选项,其中任何一个选项都是可行的选项;让我们在下面探讨这些选项。

  • Raw pointer
  • shared_ptr<T>
  • unique_ptr<T>

这些中的每一个在使用中都有自己的优点。


由于您在示例中使用了raw;我先从那个开始:

.raw

  • Pro:-您可以灵活地管理自己的记忆,但这是以更高的责任为代价的。
  • Con:-它容易出现内存泄漏,悬空和无效指针。

shared_ptr

  • Pro:-为您管理内存;并且可以跨多个对象访问,因为它是通过引用计数共享内存。
  • Con:-它基于这样的假设,即您永远不会因为使用此智能指针而面临内存泄漏或悬空指针,而此智能指针并不总是保证释放,但通常在大多数情况下是。有时,您可能不希望跨多个对象访问指针。它还因引用计数而对性能有小的影响。

unique_ptr

  • Pro:-与上述几乎相同,只有一个对象可以拥有它,从而为不需要的访问提供更多保护。
  • Con:-与上述类似,假设内存将始终被释放。如果所需的功能确实需要多个对象或源才能在将来的某个时间点访问它,则使用此类型的指针会受到限制。您可以转让所有权,但不能通过多个对象进行访问。

最后,它归结为您想要使用哪种类型的特定需求。在你的特定情况下,如果在类中使用原始指针是private members,那么在类中使用原始指针并没有错,但是在处理内存的分配和释放时,你有更多的工作要管理类,需要更多的良心。如果使用unique_ptr那么就知道内存对象是否严格地位于相关类对象内部的问题。如果使用shared_ptr那么就知道哪些外部对象将引用它。


最后你问:

What kind of pointer should I use?

从上述信息中获取知识并了解您正在使用的对象类型,让我们考虑 BST 的作用或负责的内容以及它作为类对象的主要角色。

我们知道这是一种通常与Binary Search一起使用的Binary Space Partitioning Tree。其中一个是data structure,另一个是searching algorithm.

它是一棵树,由一组nodes组成,每个node都有2 leaf nodes.树中的第一个node通常称为roothead,其中没有数据或emptyterminating node的叶节点通常称为tail,通常设置为nullnullptr。我们可以看到这些节点的关系,并知道BST将至少具有root节点的ownership。这样,BST对象的每个实例都将是独一无二的。例:

BST tree1; // Tree 1
BST tree2; // Tree 2
// Not valid code below but shown to illustrate a concept
tree1.root != tree2.root; // These two roots are not equal as in not the same memory.

这就是我们希望保持一棵树与另一棵树唯一的原因,由于这种行为,我们真的不想使用shared_ptr.对于这个特殊的类,我认为如果不使用raw pointers和管理自己的内存并使用智能指针来显示多个对象之间的ownershipuniqueness,那么更好的选择unique_ptr将是选择的对象。


在设计类并尝试决定使用哪种smart pointer时,这些是您应该自己问和回答的基本问题:

  • 这个对象have a吗?如果是;它是单独拥有它还是每个实例的内部存储器都需要是唯一的?如果是;然后使用unique_ptr
  • 是否必须跨多个对象引用此对象?如果是,请使用shared_ptr.

以下是一些参考资料:一个来自论文,另一个来自 Q/A,一个来自代码审查:

  • BST-SmartPointers.pdf
  • 堆栈溢出:唯一而不是在BST中共享
  • 堆栈代码审查:带智能指针的 BST

这些参考资料还可以帮助您做出明确的决定。

最新更新