11

据我所知,如果发生未捕获的异常,C++ 会立即销毁局部变量,Java 释放引用并将其余部分留给垃圾收集器。

这是正确的吗?在这个问题上,Java 和 C++ 到底有什么区别?换句话说,就堆栈展开问题而言,这两种语言中的哪一种被认为更好?:)

4

4 回答 4

10

我会为此而发火,但是...

在堆栈展开方面,C++ 比 Java 更胜一筹——没有竞争。C++ 对象析构函数一直沿堆栈返回,直到到达捕获点——沿途优雅地释放所有托管资源。

正如您所说,Java 将所有这些都交给了非确定性垃圾收集器(最坏的情况),或者由您在代码中乱扔垃圾的任何明确制作的 finally 块的手中(因为 Java 不支持真正的 RAII) . 也就是说,所有的资源管理代码都在每个类的客户手中,而不是在应该在的类设计者手中。

也就是说,在 C++ 中,堆栈展开机制只有在您小心确保析构函数本身不会发出异常时才能正常工作。一旦你有两个活跃的异常,你的程序abort()就不会通过 go(当然也不会触发任何剩余的析构函数)。

于 2010-03-31T08:54:48.530 回答
5

堆栈展开是专门调用调用链上所有完全构造的对象的析构函数,直到捕获异常的点。

Java 根本没有堆栈展开——如果抛出异常,它不会对对象做任何事情。您必须自己处理对象catchfinally块。这主要是 C# 引入using语句的原因- 它们简化了 IDisposable.Dispose() 的调用,但同样,这并不是 C++ 堆栈展开的完全替代品。

于 2010-03-31T08:37:29.143 回答
2

对于堆栈,两者都做同样的事情:它们为您留下异常的块释放堆栈。在 Java 中,所有原始类型(int、double 等)都直接保存,这种类型的局部变量在这一刻被释放。所有对象都通过局部变量中的引用保存,因此引用被删除,但对象本身仍保留在堆上。如果这是对该对象的最后一次引用,它们将在下一次垃圾回收时释放。如果在 C++ 中是在堆上创建的对象并且局部变量保留一个指针,那么堆上的对象不会自动释放,它们会永远留在堆上(是的,你会得到一个内存泄漏)。如果您在堆栈上保存了对象,则调用析构函数(并可能释放堆上的其他引用对象)。

于 2010-03-31T09:06:58.407 回答
2

你说得很对,C++ 以相反的顺序销毁所有局部变量,因为它退出堆栈上的每个函数 - 就像你以编程方式执行 return - 并退出main().

于 2010-03-31T08:47:54.787 回答