实现树形结构最安全的方法是什么?

What is the safest way to implement a tree structure?

本文关键字:方法 是什么 安全 结构 实现      更新时间:2023-10-16

我想在程序中创建一个树形结构。现在我有类似于下面的内容:

class tree_node
{
    public:
        tree_node (tree_node* parent) : parent_(parent)
        {
            parent_.add_child(this);
        }
    private:
        std::vector<tree_node*> children_;
        tree_node* parent_;
}

我对这个设计的主要关注是tree_node类可以删除它的任何子类和父类。我想改变设计,不允许这种情况发生。所以:

  • 我能以某种方式改变设计使用引用而不是指针吗?(引用向量不起作用)。
  • 如果我使用引用,我如何处理根节点的特殊情况(没有父节点)?
  • 我可以禁止tree_node班删除孩子/家长吗?

一种安全的解决方案是将子指针存储为boost::shared_ptr,并将父指针存储为原始指针。然后根节点将其父节点设置为null

:

  • 我能以某种方式改变设计使用引用而不是指针吗?(引用向量不起作用)。

在这种情况下必须使用指针。引用根本不起作用。

  • 我可以禁止通过tree_node类删除子节点/父节点吗?

在设计树时,最常识性的所有权模型是节点拥有其子节点的所有权,而不是相反。

你是在说你想禁止一个类对它自己做一些事情。这怎么说得通呢?如果你不想让你的类删除它自己的子类,那就不要这样做。

编辑:回答标题中而不是文本中提出的问题:最安全的方法是不要重新实现树。使用标准库关联容器或可能的boost BGL。

您可以在容器中使用引用包装器类(如果需要,可以使用boost::optional为父引用保存这样的包装器),但我不确定这是对您的潜在问题的解决方案。tree_node类不做任何内存管理,所以没有特别的删除风险。

接下来,你真的需要一个n元树吗?你能摆脱std::map或其他关联容器之一,并避免编码一堆bug吗?

显然,树的公共API不应该提供对节点类的直接访问(查看map及其对迭代器的使用),所以只要树正确地管理内存,您对指针管理的担忧应该是最小的,因为您完全控制了节点的所有管理。

你的类不做任何内存管理,因此它不会删除任何其他节点。如果你想确保任何使用tree_node类的人不会删除任何父类或子类,你需要把它们放到一个纯虚拟基类中(它们是私有的),并让tree_node继承它。使用tree_node的用户将被迫使用您提供的方法。

同样,如果你不想太担心指针,可以使用智能指针(参见boost::shared_ptr)

我可以理解为什么不能允许子节点删除父节点,但我不明白为什么要禁止删除子节点。这是树中最基本的操作之一。