我有这种树结构:
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
上执行<) / p>
到目前为止,除了析构函数之外,所有方法都正常工作。这是我的第一个析构函数,我想出了以下递归尝试,但不知道它为什么不能工作。
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;
}
结果是&#34;输入〜左子节点&#34;
的无限输出答案 0 :(得分:3)
“(我知道~tode()无论如何都会在主函数末尾的所有对象上运行,但我想确保它首先在根r上执行)”
这句话足以说明这个问题的所有内容都只是基于误解。
尝试纠正甚至没有意义:完全重写是必要的。
而是阅读更多关于析构函数,它们的调用以及它们的用途。
显式调用它不会抑制它的隐式调用。双重破坏是不明确的行为。
同样delete this
是非常棘手的,需要你必须非常确定它意味着什么。
删除它们后访问类方法(this->...
)或数据......只是在寻找麻烦。
答案 1 :(得分:1)
这是无效的,如果编译时会产生未定义的行为:
vector<node> children;
在此数据成员声明时,类node
不完整;它的大小尚不清楚。
您不能将不完整类型用作标准库容器的项类型(但您可以使用指针)。
在析构函数实现中,也是
delete this;
产生Undefined Behavior,一个无限递归调用析构函数(在此delete
表达式中)调用自身,依此类推。
数据成员声明
string& name;
也有一种强烈的,令人不快的气味,但由于你没有展示构造函数的实现,我不能断言100%它是错的。
然而,考虑到其余的代码,这种正确的可能性是无穷小的。只需使用
string name_;
答案 2 :(得分:1)
通常,树使用在免费商店中分配的节点。这意味着贩卖指向节点的指针,并删除不再使用的节点。问题中的代码不遵循该模型:它在堆栈上分配根节点,并存储节点对象而不是每个节点内的指针。使用该代码,所有编译器生成的析构函数都可以正常工作。不需要任何用户定义的析构函数。