从构造函数中抛出未处理的异常会发生什么?对于Java和C ++?会有内存泄漏吗?
答案 0 :(得分:7)
你问,
“从构造函数中抛出未处理的异常会发生什么?对于Java和C ++?会有内存泄漏吗?“
未处理的异常是一个没有关联处理程序的异常。
在C ++中,任何未处理的异常都会终止程序。在这种情况下,未指定堆栈是否展开,即,可以根据编译器执行或不执行成功构造的局部变量的析构函数。抛出异常(例如在构造函数内部)是无关紧要的。
C ++11§15.3/ 9 :
“如果找不到匹配的处理程序,则调用函数std::terminate()
;在对std::terminate()
的调用是否为实现定义之前,堆栈是否已展开。“
Java中未处理的异常同样必然会终止程序,或者至少是当前线程,如果它不是主线程,但保证调用finally
子句:
Java SE 7语言规范§11.3:
“如果找不到可以处理异常的catch
子句,则终止当前线程(遇到异常的线程)。在终止之前,所有finally
条款已执行[...]“
由于程序终止,实际上程序本身没有内存泄漏,因为在实践中操作系统会在进程后清理。
但是,崩溃程序可能会在磁盘上留下临时文件,并且可能会泄漏服务器进程中的其他资源,包括这些服务器进程中的内存泄漏。
答案 1 :(得分:6)
对于Java:控制流返回给调用者,就像从常规方法抛出异常一样。没有内存泄漏(半构造的实例将被丢弃并被垃圾收集)
答案 2 :(得分:2)
好吧,至少在C ++中,一个未处理的异常会一直持续到它的main(),从而关闭你的程序。然后,操作系统将处理未释放的内存。
不确定是否能回答你的问题......?
所以,基本上,就像它是从任何其他函数抛出的那样。
答案 3 :(得分:1)
如果在构造函数中创建依赖对象,则可能会发生内存泄漏。
在任何语言/环境中,如果这些家属被外部实体引用而无法清除,则可能会导致泄露。
在JAVA和C#中,如果不依赖外部参与,则不会导致泄漏。垃圾收集器最终会清理干净。
在C ++中,如果没有外部引用dependents,这肯定会导致泄漏。
请参阅Jon的答案,了解更多可能性:Can constructors throw exceptions in Java?
答案 4 :(得分:0)
值得补充的是:
1)Java区分“已检查”和“未检查”异常
2)应该“检查”大多数用户定义的异常。这意味着代码甚至不会编译,除非调用链中的每个模块a)处理异常,或b)明确标记它可以“抛出”异常
答案 5 :(得分:0)
对于C ++,答案在C ++ FAQ中。
How can I handle a constructor that fails?
How should I handle resources if my constructors may throw exceptions?
来自GOTW的更多信息
答案 6 :(得分:-1)
是否会出现内存泄漏取决于代码的编写方式。如果您编写“好”代码,则不应该有内存泄漏。但是完全有可能提出一个可怕的错误方案。
如果构造函数在构造函数中分配任何内容,那么事情可能会出错。
解决方案,一般是使用所谓的“两阶段构造”,因此构造函数本身非常简单并且“不会出错”。一旦构造了对象,就可以调用一个成员函数,该函数以可能失败的方式填充对象,然后你可以随意抛出异常,只要确保析构函数在某一点上运行,一切都应该运作良好。谨防“析构函数中的部分构造对象”tho' - 如果你的指针为NULL,或者如果还没有在析构函数的中途构造其他东西,会发生什么。
[上面的内容是“在我们回到main之前某处有一个处理程序,我们确实想做除了中止整个程序之外的其他事情”]。
答案 7 :(得分:-1)
两种语言(C ++或Java)的情况类似但不同。
当抛出异常时,它会向上传播回堆栈,寻找处理程序。在C ++或Java中,它可能永远不会找到一个,因此一直放回到开始并终止程序。在Java中,有一个检查异常的概念,强制执行某种异常处理(如果选中)。在C ++中,有一个异常规范的概念,但它是不切实际的(设计不合理)而且不应该使用,因此,在C ++中将所有异常都视为“未经检查”。
异常是否最终会终止程序,或者被引发到远离抛出位置的某个地方,导致这一过程的展开过程非常重要。如果它最终终止程序,那么,当然,OS没有内存泄漏,因为OS回收内存。你需要担心的是:
当堆栈展开时,在C ++中,简单地说,保证完全构造的每个堆栈绑定对象(包括正在构造的对象的数据成员或基类实例)将被立即销毁(即,确定性地),与它们的创建顺序完全相反。因此,只要所有资源直接绑定到对象的构造/销毁(也称为“RAII”),在展开过程中就不会有(内存或其他资源)泄漏,因为成功获取的每个资源都将被释放(除非在展开过程中释放资源失败,这是您需要小心处理的事情。)
在Java中,“堆栈”展开以相同的方式发生,除了不是立即销毁对象,它们被标记为丢弃(即,被垃圾收集),并最终在未来的某些不确定点被销毁。这保证没有内存泄漏,只要垃圾收集器保持活动足够长时间来完成它的工作,我不确定如果程序最终终止于未处理的异常(但在那一点无关紧要) 。 Java中的主要问题是其他资源。必须在finally
块中释放这些资源。保证在展开期间执行finally
块,但是,当然,它们必须包含用于释放在相应的try
块中分配的资源的代码。只要程序员完成了他的工作,资源就不会泄漏。
从构造函数抛出异常的事实确实没有多大区别,并且基本规则与抛出异常时不泄漏资源的基本规则相同:
在这两种情况下,您都必须彻底释放资源(禁止扔掉)。