简体   繁体   English

通用二进制搜索树中的根应使用哪种类型的指针?

[英]What type of pointer should I use for the root in a generic binary search tree?

This is the header of my generic binary search tree. 这是我的通用二进制搜索树的标头。 For now I'm just using a raw pointer for the root of the tree. 现在,我只是将原始指针用于树的根。 What kind of pointer should I use? 我应该使用哪种指针? Some of the types are unique,shared,(smart pointers) weak , and raw and on and on. 其中一些类型是唯一的,共享的((智能指针))weak和raw以及on和on。 . . . .

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();
};

Use a std::unique_ptr as it is very unlikely you want two separate BST objects to share the same implementation nodes. 使用std::unique_ptr ,因为它是不太可能你想要两个独立的BST对象共享相同的实现节点。 Usually, in that case, you would just use an external reference or (possibly) an external std::shared_ptr to the BST object itself. 通常,在这种情况下,您只需要对BST对象本身使用外部引用或(可能)外部std::shared_ptr

It just depends on what you want to do. 这仅取决于您要做什么。 I would suggest that best practice would be to use either std::unique_ptr<> or std::shared_ptr<> to make sure the memory is properly released when no longer needed. 我建议最好的做法是使用std::unique_ptr<>std::shared_ptr<>以确保不再需要该内存时可以正确释放该内存。 However, a raw pointer can work here, although you will have to handle the deallocation by yourself. 但是,尽管您必须自己处理释放,但是原始指针可以在这里工作。 In general, the benefits of smart pointers for handling and owning dynamically allocated memory tend to outweigh the benefits of using raw pointers. 通常,智能指针用于处理和拥有动态分配的内存的好处往往超过了使用原始指针的好处。

In more detail but at a high level: 更详细但更高级的:

  • Raw pointer -- handles the problem but you just have to manage deallocation if you no longer need this memory anymore. 原始指针-处理问题,但是如果您不再需要此内存,则只需管理释放。 You could accidentally deallocate the memory in one object/function when some other object still has a pointer to it 当某个其他对象仍然具有指向它的指针时,您可能会意外地在一个对象/函数中释放内存
  • std::unique_ptr<> -- will manage the memory over its lifetime, good if you don't have to share the pointer with any other object std::unique_ptr<> -将在内存的整个生命周期内对其进行管理,如果您不必与任何其他对象共享指针,那将是一个很好的选择
  • std::shared_ptr<> -- also will manage the memory, adds a bit of overhead by reference counting how many std::shared_ptr<> s also are watching the memory location. std::shared_ptr<> -也将管理内存,通过引用计数也在监视内存位置的std::shared_ptr<>增加一点开销。 This will also make sure the memory is only removed once no other std::shared_ptr<> object is pointing to it 这还将确保仅在没有其他std::shared_ptr<>对象指向它之后才删除内存。
  • std::weak_ptr<> -- can only be used in combination with std::shared_ptr<> , used to prevent reference cycles for the same object in memory std::weak_ptr<> -只能与std::shared_ptr<>结合使用,用于防止内存中同一对象的引用周期

There isn't necessarily a wrong answer. 不一定有错误的答案。 It just depends on your desired implementation. 这仅取决于您所需的实现。 The only type you should never use is std::auto_ptr<> , so avoid that type. 您永远不应使用的唯一类型是std::auto_ptr<> ,因此请避免使用该类型。

When looking at your code sample there are 3 options that come to mind where any of them could be viable options; 在查看代码示例时,会想到3个选项,其中任何一个都是可行的选项。 let's explore these options below. 让我们在下面探索这些选项。

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

Each of these have their own cons & pros in their usage. 这些工具在用法上各有优点和缺点。


Since you are using raw in your example; 由于您在示例中使用raw I'll start with that one first: 我首先开始:

raw 生的

  • Pro: - You have the flexibility to manage the memory your self, but it comes at the cost of a higher responsibility. Pro: - 您可以灵活地管理自己的内存,但这要付出更高的责任。
  • Con: - It is prone to memory leaks, dangling & invalid pointers. Con: - 容易出现内存泄漏,悬空和无效指针。

shared_ptr shared_ptr

  • Pro: - Manages the memory for you; Pro: - 为您管理内存; and is accessible across multiple objects as it is shared memory via reference counting. 并且可以通过引用计数在多个对象之间进行访问,因为它是共享内存。
  • Con: - It is based on the assumption that you will never face a memory leak or dangling pointer just because of using this smart pointer where it is not always guaranteed to be released but usually is in most cases. Con: - 基于这样的假设:您永远不会因为使用此智能指针而面临内存泄漏或指针晃动的情况,在这种情况下并不总是保证它会被释放,但通常在大多数情况下会被释放。 Sometimes you may not want a pointer to be accessible across multiple objects. 有时,您可能不希望跨多个对象访问指针。 It also has a small performance hit from reference counting. 从引用计数来看,它的性能也会受到影响。

unique_ptr unique_ptr

  • Pro: - Nearly same as above only that one object can own this providing more protection of unwanted access. Pro: - 与上述几乎相同,只有一个对象可以拥有此对象,从而为不必要的访问提供了更多保护。
  • Con: - Similar as above under the assumption that the memory will always be freed. Con: - 与上面类似,但假定将始终释放内存。 If the functionality needed does require multiple objects or sources to access this at some future point in time, then you are limited by using this type of pointer. 如果所需的功能确实需要多个对象或源在将来的某个时间点进行访问,则使用这种类型的指针会受到限制。 You can transfer ownership but you can not access via multiple objects. 您可以转让所有权,但不能通过多个对象进行访问。

In the end it comes down to your particular need of which type you will want to use. 最后,它取决于您要使用哪种类型的特定需求。 In your particular situation there is nothing wrong with using raw pointers within the class if they are private members but you have more work to manage the class and more to be conscience of when dealing with the allocation & releasing of memory. 在您的特定情况下,如果类中的原始指针是private members ,那么在类中使用原始指针是没有错的,但是您有更多的工作来管理该类,并且在处理内存的分配和释放时要有更多的良心。 If using unique_ptr then it is a matter of knowing if the memory object will be strictly internal to the pertaining class object or not. 如果使用unique_ptr ,则要知道内存对象是否严格位于相关类对象的内部。 If using shared_ptr then it is a matter of knowing which external objects will be referencing it. 如果使用shared_ptr ,则只需知道哪些外部对象将引用它即可。


In the end you had asked: 最后,您问:

What kind of pointer should I use?

Taking the knowledge from the above information and by understanding the type of object you are working with, let's consider what the BST does or is responsible for and its primary role as a class object. 从以上信息中获得知识,并通过了解您正在使用的对象的类型,让我们考虑一下BST做什么或负责什么以及它作为类对象的主要作用。

We know that it is a Binary Space Partitioning Tree typically used with a Binary Search . 我们知道这是通常与Binary Search一起使用的Binary Space Partitioning Tree Where one is the data structure and the other is the searching algorithm . 其中一个是data structure ,另一个是searching algorithm

It is a tree that consists of a set of nodes and each node has 2 leaf nodes . 它是由一组nodes组成的树,每个node2 leaf nodes The very first node in the tree is typically called the root or the head where a leaf node that has no data or is empty a terminating node is normally called the tail and is usually set to null or nullptr . 树中的第一个node通常称为roothead节点,其中没有数据或为empty的叶节点的terminating node通常称为tail ,通常设置为nullnullptr We can see the relationship of these nodes and know that the BST will have ownership of at least the root node. 我们可以看到这些节点的关系,并且知道BST将至少拥有root ownership This way each instance of a BST object will be unique from another. 这样, BST对象的每个实例在另一个实例中都是唯一的。 Example: 例:

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.

This is what we would want to keep one tree unique from another and because of this behavior we really wouldn't want to use shared_ptr . 这就是我们想要使一棵树与另一棵树保持唯一性的原因,由于这种行为,我们确实不希望使用shared_ptr With this particular class I think the better option here if not using raw pointers and managing your own memory and using smart pointers to show ownership and uniqueness between multiple objects that unique_ptr would then be the one to choose. 对于这个特定的类,我认为如果不使用raw pointers并管理自己的内存并使用智能指针来显示多个对象之间的ownershipuniqueness ,那么unique_ptr将是一个更好的选择。


When designing classes and trying to decide which smart pointer to use these are the basic questions you should ask & answer yourself: 在设计类并尝试确定使用哪种smart pointer ,您应该问自己以下基本问题:

  • Does this object have a ? 这个物体have a吗? If yes; 如是; does it solely own it or does each instance's internal memory need to be unique? 它是完全拥有它还是每个实例的内部存储器需要唯一? If Yes; 如是; then use a unique_ptr 然后使用unique_ptr
  • Does this object have to be referenced across multiple objects? 是否必须跨多个对象引用该对象? If yes, then use shared_ptr . 如果是,则使用shared_ptr

Here are a few references: One from a paper and another from and Q/A, one from code review: 这里有一些参考:一个来自论文,另一个来自Q / A,一个来自代码审查:

These references may also help you into making a well defined decision. 这些参考也可以帮助您做出明确的决定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM