我必须手动解构所有对象吗

Posted

技术标签:

【中文标题】我必须手动解构所有对象吗【英文标题】:do i have to manually deconstruct all objects 【发布时间】:2016-06-09 20:40:19 【问题描述】:

我创建了一个名为 BST 的类,它有一个成员根。我知道当我调用 BST 类的解构函数时,它会删除根目录并释放该类占用的内存。

我想知道,解构器是否会解构所有与 BST 对象关联的节点。即 root 的左孩子和右孩子以及他们的左孩子和右孩子等等。

我的猜测是没有。在这种情况下,我认为我将不得不进行后序遍历并手动删除每个节点。有没有办法一次完成。无需在树节点周围走动

#ifndef BST_H
#define BST_H
#include "bst.h"
#include <stdio.h>
#include<iostream>

class bst

protected:
    struct node

        node* p;
        node* lc;
        node* rc;
        int key;
        node(int x,node* p=nullptr,node* lc=nullptr,node* rc=nullptr):key(x)

        
        ~node()
        std::cout<<"decontrucotr node";
        

    ;
    node* nil=new node(0);
    node* root;


public:


    bst();
    virtual ~bst();
    void put(int x);
    void in_order(node* x);
    void in_order();
    void pre_order(node* x);
    void pre_order();




    private:
;

#endif // BST_H

函数在此定义

#include "bst.h"
#include <stdio.h>
#include<iostream>

bst::bst():root(nil)






bst::~bst()


std::cout<<"deconstructor tree"<<'\n';


void bst::put(int x)


node* k=new node(x,this->nil,this->nil,this->nil);
node* y=this->root;
node* p=y;
while (y != nil)

    p=y;
    if (y->key>x)
        y=y->lc;
    
    else
        y=y->rc;
    

if (p==nil)
    this->root=k;
    k->lc=this->nil;
    k->rc=this->nil;
    k->p=this->nil;

else if(p->key>x)
    p->lc=k;
    p->lc->p=p;
    k=p->lc;
    k->lc=this->nil;
    k->rc=this->nil;

else
    p->rc=k;
    p->rc->p=p;
    k=p->rc;
    k->lc=this->nil;
    k->rc=this->nil;



void bst::in_order(node* x)
if(x != nil)
this->in_order(x->lc);
printf("%d%c",x->key,'\t');
this->in_order(x->rc);


void bst :: in_order()
this->in_order(this->root);
printf("%c",'\n');


void bst::pre_order(node* x)
    if(x!=this->nil)
    printf("%d%c",x->key,'\t');
    pre_order(x->lc);
    pre_order(x->rc);




void bst::pre_order()
pre_order(this->root);

printf("%c",'\n');

【问题讨论】:

快速提问:您研究过 STL 的智能指针吗? ***.com/questions/106508/… en.cppreference.com/w/cpp/memory/shared_ptr 如果您需要使用原始指针或不能使用 C++11 或更高版本,我深表歉意,但如果不是,请查看智能指针.内存管理可以是一个真正的熊。 @Wikiti 我认为你的意思是每个new 都应该有一个delete。可能听起来像吹毛求疵,但有时言语很重要。它既不称为“破坏”也不称为“解构”,但必须删除新对象(这包括调用析构函数,但这还不是全部)。 @Ian:不,每次你有新东西时,都用std::unique_ptr替换它。 @WilliamKappler newdelete 比托管指针更受欢迎的例子有哪些?我能想到的只是我将数据返回到显然不能使用托管指针的 C 代码的情况。即使那样,我也会使用unique_ptr,直到我准备好释放并返回指针。 我在 20 年前学习了 C++。我对 new 和 delete 很满意。 【参考方案1】:

我创建了一个名为 BST 的类,它有一个成员根。我知道当我调用 BST 类的解构函数时,它会删除根目录并释放该类占用的内存。

在您展示的实现中,~bst 析构函数本质上是空的(日志不计算在内),它根本没有释放任何节点。

我想知道,解构器是否会解构所有与 BST 对象关联的节点。

bst 对象本身已被破坏。它的子节点不是,不是。

即 root 的左孩子和右孩子以及他们的左孩子和右孩子等等。

不在当前实现中,不。您需要编写该逻辑。

在这种情况下,我认为我将不得不进行后序遍历并手动删除每个节点。

在当前的实现中,是的。

有什么方法可以一次性完成。无需在树节点周围走动

要么:

    编码~node 析构函数以删除其直接子节点。然后~bst析构函数可以删除它的root节点,它下面的所有其他节点都会被递归删除。

    使用智能指针,例如std::unique_ptr,而不是原始指针。让编译器为您完成所有工作。

【讨论】:

拥抱现代 c++!【参考方案2】:

“我必须手动解构所有对象吗?”

是的,因为 C/C++ 不跟踪内存,您告诉它您将自行管理,这就是使用 new 和/或 malloc 隐含的意思。

如果您愿意,thereareoptions 可以用于不同的用例。但是,除此之外,您必须始终将每个分配 (new) 与恰好 1 个解除分配 (delete) 配对。

“我想知道,解构器会解构所有与 BST 对象相关的节点吗?”

不,因为你没有告诉它。

你应该:

~node()

    std::cout<<"decontrucotr node";
    delete lc;
    delete rc;

也就是说,bst::put(int x) 对我来说毫无意义,我发现其中很可能存在类似的错误。您应该努力编写文档化、清晰的代码——尤其是当您打算向其他人寻求帮助时。

【讨论】:

你所说的创建了一个无限递归 @Nikhil Infinite recursion 在删除操作中应该是不可能的。如果你让一个孩子成为自己的父母(甚至间接地),当你尝试 delete 一个对象两次时,我预计会崩溃,至少如果你将它构建为调试。也许没有调试就可以发生无限递归;这将是未定义的行为。如果它只是一直运行而不会崩溃,我建议您添加一些调试功能以将节点结构打印到控制台,如果原因不明显,请提出单独的问题。 当我删除 cout 时它崩溃了。但是使用 cout 它只是继续打印用解构函数编写的字符串。我做了一个哨兵对象 nil 是因为那个吗? nil 就在那里,所以当我从这个类继承到红黑树时 @Nikhil 实际上,我没有意识到这一点。为什么要使用哨兵对象代替 null?使用 null 或 nullptr 表示空指针。 delete 在 null 上是无操作的。对象上的delete,即使您称其为“nil”,也会删除该对象。所以,现在我看着它,递归地删除nil。至于打印不会使其崩溃......未定义的行为。不知道为什么会修复崩溃,但打印到控制台本身并没有真正影响这一点。 是的,没有 nil 它会起作用,我首先尝试过,但对于红黑树,我需要 nil。 nil sentinel 使编码更容易,它只是一个帮助工具。我一直在寻找一种方法,即使在 nil 的情况下也能正常工作。

以上是关于我必须手动解构所有对象吗的主要内容,如果未能解决你的问题,请参考以下文章

升级的 Python;我是不是必须手动重新安装所有站点包?

手动挡汽车行驶中踩刹车必须踩离合器吗?

我需要手动取消订阅吗? - Angular 8 [重复]

如果我之前手动添加文件,我可以让 git 拒绝所有提交吗?

我可以“手动”将项目插入 AFIncrementalStore 的缓存吗?

这种手动去虚拟化合法/可行吗?