【问题标题】:Memory allocation error when attempting to print contents of a tree in C++尝试在 C++ 中打印树的内容时出现内存分配错误
【发布时间】:2020-05-03 19:51:50
【问题描述】:

我的问题可能有一个简单的解决方案让我眼前一亮,但到目前为止我一直无法找到它。我对 C 语言很陌生,这是我用 C++ 编写的第一个程序。

我有一个函数create_complete_tree(int nr_child_nodes, int tree_depth),它生成一个深度树int tree_depth,其中每个节点(最后一行除外)都有int nr_child_nodes 个子节点。 create_complete_tree(2,4) 制作一棵树,开头是这样的:

                      1
                     / \
                    /   \
                   2     9
                  / \   / \
                 3   6 10 13
                /\   /\/\ /\
                     ...

我正在尝试创建一个函数print(std::ostream& str),当在上面树的根节点上调用它时,会以这种格式打印树的内容:

node_1
   node_2
      node_3
         node_4
         node_5
      node_6
         node_7
         node_8
   node_9
      node_10
         node_11
         node_12
      node_13
         node_14
         node_15

我会担心稍后添加缩进,但现在我只专注于以正确的顺序打印节点。这是我目前所拥有的:

void node::print(std::ostream& str) {
    str << this->get_name() << std::endl;

    for (int i = 0; i < this->get_nr_children(); i++) {
        node child = (*this->get_child(i));
        child.print(str);
    }
}

此函数将节点 1-8 打印出来,但随后出现 Segmentation fault: 11 错误。我知道此错误是由于尝试访问以某种方式不可用/不受限制的内存而导致的,但我很难理解这在我的情况下的真正含义。我的create_complete_tree 方法如下所示:

void node::create_complete_tree(int nr_child_nodes, int tree_depth) {
    if (tree_depth == 1) {
        return;
    } else {
        while (this->get_nr_children() < nr_child_nodes) {
            node* new_child = new node();
            this->add_child(new_child);
            (*new_child).create_complete_tree(nr_child_nodes, tree_depth - 1);
        }
    }
}

每个节点的子节点指针存储在一个名为child_nodes 的向量中。感谢您抽时间阅读。如果有任何回复可以帮助我找到解决方案并更好地理解内存分配,我将不胜感激。

【问题讨论】:

    标签: c++ pointers tree segmentation-fault


    【解决方案1】:

    问题

    此代码很可能侵犯了the rule of 3。以下声明:

        node child = (*this->get_child(i));
    

    创建节点的克隆。如果您没有提供规则 3,但实现了析构函数,则克隆将使用与原始节点相同的指向相同子节点的指针。不幸的是,当您离开print() 函数时,克隆被破坏,而析构函数将破坏子代。随后对这些子项的所有访问都将访问一个不再存在的对象,即 UB。

    Segfault 可能是 UB 的症状。如果没有看到node 的构造函数、复制构造函数、赋值和析构函数实现,我无法确定。但是看到这段代码,还有很多类似的问题,我会很惊讶这会是另一个问题;-)

    可能的解决方案

    无论如何,正确的解决方案是实现 trule 3 中缺少的内容。因为如果不这样做,您将在许多情况下遇到类似的问题。

    另一种解决方案(不是互斥的)是使用指针而不克隆:

    void node::print(std::ostream& str) {
      str << this->get_name() << std::endl;
    
      for (int i = 0; i < get_nr_children(); i++) { // this-> is not needed
        node *child = this->get_child(i);         // pointer assignment without cloning
        child->print(str);                        // member invokation for a pointer
      }
    }
    

    【讨论】:

    • 您好,谢谢您的回复。这是我第一次听说 3 规则,所以我一定会看看它。
    猜你喜欢
    • 2020-04-23
    • 2012-07-01
    • 2019-11-23
    • 2019-12-29
    • 1970-01-01
    • 2018-02-08
    • 2016-05-08
    • 1970-01-01
    • 2022-12-12
    相关资源
    最近更新 更多