【问题标题】:C++ destructor for tree structure用于树结构的 C++ 析构函数
【发布时间】:2023-03-15 16:12:02
【问题描述】:

我有这个树结构:

public:
    node(string& const n);
    virtual ~node();
    string get_name() const;
    void set_name(string& new_name);
    int get_nr_children() const;
    node get_child(int i) const;
    void add_child(node child);
private:
    string& name;
    vector<node> children;
};

我的 main.cpp 看起来像这样:

int main() {
    string s = "root";
    node r(s);
    string s2 = "left child";
    node ls(s2);
    string s3 = "right child";
    node rs(s3);

    r.add_child(ls);
    r.add_child(rs);

    r.~node();
}

(我知道~node()main 函数的末尾无论如何都会在所有对象上运行,但我想确保它首先在根r 上执行)

到目前为止,所有方法都运行良好,除了析构函数。这是我的第一个析构函数,我想出了下面的递归尝试,但不知道为什么它不起作用。

node::~node() {
    cout << "Enter ~node of " << this->get_name() << endl;
    while (this->get_nr_children() != 0) {
        this->get_child(0).~node();
        this->children.pop_back();
    }
    delete this;
    cout << "Leave ~node of " << this->get_name() << endl;
}

结果是“Enter ~node of left child”的无穷输出

【问题讨论】:

  • 不要直接调用析构函数。而是使用delete(更好的是:使用容器或智能指针)。
  • 但仅在指向您使用 new 分配的对象的指针上调用 delete
  • delete this 来自析构函数?真的吗?
  • void main 在 C 或 C++ 中从未有效。带有void main 的代码会教给初学者一个坏习惯,这意味着大多数读者不能只是复制和粘贴代码来尝试一下。请不要使用void main 发布代码。谢谢你。 FTFY。
  • @PattuX 让智能指针甚至是相关的,你需要有指针......你似乎根本没有。您的孩子是node 中的vector,因此与delete 无关。

标签: c++ tree destructor


【解决方案1】:

"(我知道 ~node() 在主函数结束时无论如何都会在所有对象上运行,但我想确保它首先在根 r 上执行)"

这句话足以说明这个问题的所有内容都只是基于误解。

尝试纠正甚至没有意义:需要完全重写。

请阅读更多关于析构函数、它们的调用以及它们的用途。

显式调用它不会抑制它的隐式调用。双重破坏是未定义的行为。

另外delete this 是一个非常棘手的问题,要求你必须非常清楚它的含义。

而访问类方法(this-&gt;...)或删除后的数据……只是在找麻烦。

【讨论】:

    【解决方案2】:

    这是无效的,如果编译会产生未定义的行为:

    vector<node> children;
    

    在此数据成员声明处,node不完整;它的大小尚不清楚。

    您不能将不完整类型用作标准库容器的项类型(但您可以使用指针)。


    在析构函数实现中,也是

    delete this;
    

    产生未定义的行为,调用析构函数的无限递归(在此delete 表达式中)调用自身,等等。


    数据成员声明

    string& name;
    

    它也有一种强烈的、令人不快的气味,但由于你没有展示构造函数的实现,我不能断然 100% 说它是错误的。

    但是,考虑到其余代码,正确的机会是无限小的。只需使用

    string name_;
    

    【讨论】:

    • C++1z中允许第一个。
    • @T.C.;你的意思是它很可能会在 C++17 中得到支持。谢谢 我不知道。你有参考吗?
    【解决方案3】:

    通常,树使用在空闲存储区分配的节点。这意味着交易指向节点的指针,并删除不再使用的节点。问题中的代码不遵循该模型:它在堆栈上分配根节点,并在每个节点内存储节点对象而不是指针。使用该代码,所有编译器生成的析构函数都可以正常工作。不需要任何用户定义的析构函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-10
      • 2019-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多