如果我要创建一个节点类,如下所示,如果它在双向链表中使用,它会在解构双链表时创建一个无限循环吗?还是会很好地终止?
class Node
{
Node( );
~Node( )
{
delete mNext; //deallocs next node
}
Contact mContact;
Node* mPrevious;
Node* mNext;
};
编辑:如果我将代码修改为此可行吗?
~Node( )
{
mPrevious = NULL;
if (mNext->mPrevious != NULL)
{
delete mNext; //deallocs next node
}
}
编辑2:或者这会最好吗?
~Node( )
{
if (mPrevious != NULL)
{
mPrevious = NULL;
delete mNext; //deallocs next node
}
}
答案 0 :(得分:2)
如果考虑mNext
指针,节点正在形成一个循环,那么任何节点的破坏确实可能形成一个无限的递归循环,它将通过炸毁来终止程序堆栈。
可能发生的事情是
delete node;
。delete mNext;
,从而在循环中的下一个节点上触发相同的进程。node
,从而使第一次调用成为一个永远不会结束的递归。delete mNext;
是析构函数上的最后一个语句仍有操作必须在delete
运算符完成后执行。但请注意,根据我的经验,除非您使用特殊的编译器选项,否则不会检查堆栈溢出,因此程序终止将非常“异常”。另请注意,在Windows下有一些可怕的代码,如果它们在程序终止时发生,在某些情况下会隐藏段错误,因此很可能在退出事件循环后,Windows程序显然可以在此操作中正常终止。
赋予堆栈overlflow通常不会被认为确实存在任何行为,包括明显的“无限循环”(请注意,这个无限循环可能不是递归析构函数之一,但在运行时系统内某处因为堆栈溢出)。
为什么我使用这个词?原因是C ++标准说对象的多次破坏是Undefined Behavior。如果你在C ++中没有办法在没有完成销毁的情况下退出析构函数这一事实,你会理解理论上允许编译器将对象标记为“被销毁”并使守护进程飞出你的如果您输入两次相同对象的析构函数,则为nosrils。然而,检查此错误并不是必需的,并且编译器编写器通常是惰性的(这不是程序员的侮辱),因此不太可能存在此检查(除非启用了一些特殊的额外调试选项)。
总结一下:它能永远循环吗?是。可以崩溃吗?当然。它能不能告诉我一个物体被摧毁了两次?当然。它可以很好地终止程序(即设置任何错误代码)?是的,那也是。
任何事情都可能发生。墨菲说会发生任何对你造成最大伤害的事情......例如,在你开发它的过程中,程序会每次都很好地终止......而且在演示日期间它会在你脸上严重崩溃一千名潜在客户面前。
请不要这样做: - )
答案 1 :(得分:1)
没有办法知道何时停止,所以它可能无限运行
你应该编写一个List
类,它有一个指向(或实际)Node
的指针。 Node
's d'tor应该只关注自己的字段,在这种情况下mContact
。 List
's d'tor应迭代列表中的所有节点(记住何时停止),并删除每个节点(只需一次)。
答案 2 :(得分:1)
假设您将mNext初始化为null,它将无法无限运行。删除在遇到空指针时不会执行任何操作。因此它会在你期望的时候结束。
我不确定你用“if previous”选项做了什么。那些不行。这将是一个有效的节点,因此具有前一个节点或它将不是一个有效的节点,并且检查先前将有未定义的结果。坚持简单的回答:
class Node
{
Node( mNext = NULL; );
~Node( )
{
delete mNext; //deallocs next node
}
Contact mContact;
Node* mPrevious;
Node* mNext;
};
澄清:此解决方案有效,但仅在满足两个条件时: 1)列表中没有节点出现两次。 2)该清单不是循环的。 如果您能保证这些条件,这是您最简单的答案。如果你做不到,你需要做一些更复杂的事情。
答案 3 :(得分:0)
就我个人而言,我认为Node
的析构函数应该与其他节点有关,这有点奇怪。
如果设计取决于我,我会创建一个List
类,其中包含指向Node
个对象(first
和last
)的指针。 List
类的析构函数将负责迭代列表中的所有节点并销毁它们。
答案 4 :(得分:0)
这实际上很简单。 假设 1)它是一个双重链接列表而不是循环链接列表 2)链接列表中没有循环:这是双链接列表 3)实现类只有一个Node实例,可能叫做HeadNode或LinkList;)这是明确销毁的节点
示例:LinkList是1-> 2-> 3-> 4-> 5-> 6-> NULL 对HeadNode的析构函数调用(reffer 3rd assumption)将导致一个递归调用,如下所示: 删除(1) - >删除(2) - >删除(3) - >删除(4) - >删除(5) - >删除(6) - > NULL 所以请chech if(mNext!= NULL)删除mNext 它的工作原理:)
但是:如果你想特别删除一个节点:假设我们只想在上面的例子中删除4个,那么所有的节点都会被删除到NULL,所以在删除之前请确保你将Mnext设置为NULL。
最佳做法是使用STL库或以其他方式使用autopointer类来解决问题的破坏部分