如果考虑到mNext
节点正在形成一个循环的指针,那么任何节点的破坏确实可能会形成一个无限递归循环,并且它将通过炸毁堆栈来终止程序。
它可能会发生的是
- 第一个“外部”
delete node;
发行。
- 当进入节点析构函数时,还没有做任何事情,因为代码析构函数是销毁过程中执行的“第一”件事(销毁过程本身非常复杂,包括析构函数代码、类更改、成员销毁、基础销毁,顺序如下:有关更详细的解释,请参阅此答案)。
- 第一个析构指令填充执行
delete mNext;
因此在循环中的下一个节点上触发相同的过程。
- 因为节点正在形成一个循环,所以这个链将
node
再次“从后面”到达,从而使第一次调用成为永远不会结束的递归。
- 每次调用都会为激活记录分配堆栈空间,因此一段时间后所有允许用于堆栈的内存将被耗尽,操作系统将终止该进程。删除调用不是“尾调用”,因为在析构函数代码完成后,内存必须被释放,所以这个递归不能轻易地被优化掉......而
delete mNext;
析构函数的最后一条语句仍然有必须在之后执行的操作delete
运算符完成。
但是请注意,根据我的经验,除非您使用特殊的编译器选项,否则不会检查堆栈溢出,因此程序终止将非常“异常”。另请注意,在 Windows 下,有一些可怕的代码在某些情况下会隐藏 segfault 错误,如果它们发生在程序终止时,那么 Windows 程序很可能只是在退出事件循环后完成的此操作中优雅地终止。
假设堆栈溢出通常不被认为确实有任何行为是可能的,包括明显的“无限循环”(请注意,这个无限循环可能不是递归析构函数之一,而是运行时系统内部的某个地方因为堆栈溢出而变得疯狂) .
为什么我用了大概这个词?原因是 C++ 标准规定对象的多次破坏是未定义的行为。如果您将此添加到 C++ 中无法在不完成销毁的情况下退出析构函数的事实中,您将了解编译器理论上允许将对象标记为“正在销毁”并使守护程序飞出您的nosrils 如果你两次输入同一个对象的析构函数。但是,检查此错误不是强制性的,编译器编写者通常很懒惰(这不是对程序员的侮辱),因此不太可能出现此检查(除非启用了某些特殊的额外调试选项)。
总结一下:它可以永远循环吗?是的。能崩溃吗?当然。它可以停止告诉我一个物体被摧毁了两次吗?当然。它可以很好地终止程序(即不设置任何错误代码)吗?是的,那也是。
任何事情都有可能发生。墨菲说它会发生任何会对你造成最大伤害的事情......例如,当你开发它时,程序每次都会很好地终止......并且它会在你的演示日期间严重崩溃在一千名潜在客户面前。
只是不要那样做:-)