c++ - 即使我将单个节点设置为 NULL 并删除它们,递归清除二叉树也不起作用

标签 c++ memory-management binary-tree linker-errors

我试图在 MacOS 上使用 coderunner IDE 在 cpp 中创建一个二叉树结构。我应该有两个单独的文件,称为 bintree.h 和 bintree.cpp,但由于一些我无法修复的链接器错误,我无法完成这项工作。所以我只是将这两个文件合并到 binarytree.h 中并创建了一个客户端文件 main.cpp。代码编译并成功运行。但是,在检查输出后,除了 tree_clear() 函数外,一切似乎都在工作。即使在清除树之后,即使我将清除的节点设置为 NULL 然后删除它们,我仍然可以使用 print() 函数打印清除的树。为什么会这样?我在一个死胡同。请帮忙。提前致谢。
以下是我的文件 binarytree.h 的代码

#ifndef BINARYTREE_H
#define BINARYTREE_H

#include <cstdlib>  // Provides NULL and size_t
#include <iostream>
#include <iomanip>

using namespace std;

class binary_tree_node 
{

public:

// TYPEDEF
typedef int value_type;

// CONSTRUCTOR with definition
binary_tree_node(const int& init_data = int(), binary_tree_node* init_left = NULL, binary_tree_node* init_right = NULL)
{ 
    data_field = init_data; 
    left_field = init_left; 
    right_field = init_right;
}

// MODIFICATION MEMBER FUNCTIONS
int &data( ) { return data_field; }
binary_tree_node* left( ) { return left_field; }
binary_tree_node* right( ) { return right_field; }
void set_data(const int &new_data) { data_field = new_data; }
void set_left(binary_tree_node* new_left) { left_field = new_left; }
void set_right(binary_tree_node* new_right) { right_field = new_right; }


// CONST MEMBER FUNCTIONS
const int& data( ) const { return data_field; }
const binary_tree_node* left( ) const { return left_field; }
const binary_tree_node* right( ) const { return right_field; }
bool is_leaf( ) const 
    { return (left_field == NULL) && (right_field == NULL); }

private:

int data_field;
binary_tree_node *left_field;
binary_tree_node *right_field;
};
#endif



////////////////////////////////////////////
////////////////////////////////////////////
// IMPLEMENTATION CODE /////////////////////
// bintree.cpp         /////////////////////
////////////////////////////////////////////
////////////////////////////////////////////
// I had to combine files bintree.h and  ///
// bintree.cpp into one file called      ///
// binarytree.h as in Mac OS the linker  ///
// generates an error during compilation ///
////////////////////////////////////////////
////////////////////////////////////////////

void print(binary_tree_node *node_ptr, int depth) 
{
    if (node_ptr != NULL) 
    {
        print(node_ptr->right( ), depth+1);
        std::cout << std::setw(4*depth) << ""; // Indent 4*depth spaces.
        std::cout << node_ptr->data( ) << std::endl;
        print(node_ptr->left( ),  depth+1);
    }
}

void tree_clear(binary_tree_node *root_ptr) 
{
    if (root_ptr != NULL) 
    {
        tree_clear( root_ptr->left( ) );
        tree_clear( root_ptr->right( ) );
        root_ptr = NULL;
        delete root_ptr;
    } 
}

//  void tree_clear(binary_tree_node *root_ptr) 
//  {
//      if (root_ptr == NULL) { return; }
//      tree_clear(root_ptr->left());
//      tree_clear(root_ptr->right());
//      root_ptr = NULL;
//      delete root_ptr;
//  }


binary_tree_node* tree_copy(const binary_tree_node* root_ptr)
{
    // Library facilities used: cstdlib
    binary_tree_node *l_ptr;
    binary_tree_node *r_ptr;

    if (root_ptr == NULL) return NULL;
    else
    {
        l_ptr = tree_copy( root_ptr->left( ) );
        r_ptr = tree_copy( root_ptr->right( ) );
        
        return
        new binary_tree_node( root_ptr->data( ), l_ptr, r_ptr);
    }
} 
以下是main.cpp
#include <iostream>
#include "binarytree.h"

using namespace std;

int main(int argc, char *argv[]) 
{
//Constructor usage
binary_tree_node leftLeaf1(1), rightLeaf1(7), leftNode1(84, &leftLeaf1, NULL), rightNode1(120, NULL, &rightLeaf1), rootNode1(100, &leftNode1, &rightNode1);
cout << "Printing tree after creation through constructor:\n";
print(&rootNode1, 3);
//cout << "Print line address " << &rootNode1 << endl;

// Copying the tree
binary_tree_node* treeCopyRoot = tree_copy(&rootNode1);
cout << "\nPrinting treeCopyRoot after using tree_copy() to copy rootNode1:\n";
print(treeCopyRoot, 2);

//cout << "\nValue in root " << rootNode1.data();
//cout << "\nPrinting rootNode1:\n";


// Clearing the tree
tree_clear(&rootNode1);
cout << "\nPrinting tree after clearing through tree_clear:\n";
print(&rootNode1, 3);
}

最佳答案

我现在明白了。您已创建 binary_tree_node main 中的对象在堆栈上。这些对象持有的内存位置绑定(bind)到 main功能。只有在 main 时才会释放它们。功能结束。
你看tree_clear被调用,地址,&root_node1被复制到指针 root_ptr .这在分配给 NULL 时,无法访问地址 &root_node1因此delete实际上什么都不做,因为它从地址位置释放内存 NULL .如果你第一次尝试做 delete root_ptr ,由于我上面提到的原因,它会给您在评论中提到的错误。
要解决此问题,请在堆上分配内存(使用 newbinary_tree_node 中创建 main 对象)。这样内存就不会绑定(bind)到任何东西,你可以delete这个内存来自任何函数。

关于c++ - 即使我将单个节点设置为 NULL 并删除它们,递归清除二叉树也不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63050041/

相关文章:

c++ - 是否有用于获取代理用户名和密码的标准 Windows 对话框?

c++ - 为什么表达式的结果取决于表达式的放置位置?

javascript - "delete"属性的正确方法?

java - 将整数数组转换为具有给定顺序的树

c++ - 旋转矩阵/图像90度C++的公式

c++ - 抓双免并妥善处理

ruby-on-rails - Unicorn:要使用多少个工作进程?

java - Java中的树遍历

performance - 找出二叉树是否平衡或效率不高

c++ - 如何在 Mac OS X 上监视目录中的更改?