据我所知,在未捕获异常的情况下,C ++会立即销毁本地变量,Java会释放引用并将其余部分留给垃圾收集器。
这是对的吗? Java和C ++在这个问题上究竟有什么区别?换句话说,就堆栈展开问题而言,这两种语言中的哪一种被认为更好? :)
答案 0 :(得分:10)
我会因此而受到抨击......但
在堆栈展开前,C ++比Java更好 - 没有比赛。 C ++对象析构函数一直触发堆栈,直到达到捕获点 - 沿途正常释放所有托管资源。
正如你所说,Java将所有这些都置于非确定性垃圾收集器(最坏情况)的支配之下,或者放在任何明确制作的最终块中,因为Java不支持(因为Java不支持)真正的RAII)。也就是说,所有资源管理代码都掌握在每个类的客户手中,而不是应该在类设计者手中。
也就是说,在C ++中,如果你小心确保析构函数本身不会发出异常,那么堆栈展开机制只能正常运行。一旦你有两个活动的例外,你的程序abort()
没有通过去(当然也没有解雇任何剩余的析构函数)。
答案 1 :(得分:5)
堆栈展开专门调用调用链上所有完全构造的对象的析构函数,直到捕获到异常的位置。
Java根本没有堆栈展开 - 如果抛出异常,它对对象不做任何事情。您必须自己在catch
和finally
块中处理对象。这主要是为什么C#引入using
statements - 它们简化了调用IDisposable.Dispose()的原因,但这又不是C ++堆栈展开的完全替代。
答案 2 :(得分:2)
你是完全正确的,C ++以相反的顺序销毁所有局部变量,因为它退出堆栈上的每个函数 - 就好像你是以编程方式执行return - 而不是main()
。
答案 3 :(得分:2)
对于堆栈,请执行以下操作:它们释放您离开的块的堆栈,但异常。在Java中,所有原始类型(int,double等)都直接保存,此时此类型的局部变量被释放。所有对象都通过局部变量中的引用保存,因此引用将被删除,但对象本身仍保留在堆上。如果这是对象的最后一个引用,它们将在下一个垃圾回收中释放。如果在C ++中是在堆上创建的对象并且局部变量保留指针,则堆上的对象不会自动释放,它们永远保留在堆上(是的,你得到一个MEMORY LEAK)。如果已在堆栈上保存了对象,则会调用析构函数(并且可能会释放堆上的其他引用对象)。