在构造“new”对象时,如果出现异常,堆分配的内存会发生什么?

3

当一个类在构造过程中抛出异常时,分配的内存会发生什么情况?你应该如何处理这样的情况。例如:

std::auto_ptr<ThirdPartyClass> au_tpc;

try
{
    au_tpc.reset(new ThirdPartyClass());
}
catch(...)
{
    // What happened to the memory allocated of 
    // sizeof(ThirdPartyClass) for the new instance?
}

你可以尝试从C++规范中找到这个问题的答案。或者你可以花5分钟时间,自己尝试一下。创建一个带有巨大数组和抛出异常构造函数的类,并在循环中运行此代码。 - Hans Passant
4个回答

7

它只是起作用。在执行异常处理块之前,内存将被释放。


2
@JoachimPileborg 什么内存?如果构造函数抛出异常,reset 永远不会被调用。 - R. Martinho Fernandes
这只是半真的。 - Maxim Egorushkin
@MaximYegorushkin 请进一步说明。我坚信这是完全正确的。 - R. Martinho Fernandes
@MaximYegorushkin 我可以一整天提到更多的琐事。但这并不会使我所说的话变得不真实,也不会使那些琐事对于这个问题有任何更多的相关性(如果不清楚的话,那篇文章并没有解释这个问题;也许你可以试着读一下它)。 - R. Martinho Fernandes

3
C++11标准相关部分: 5.3.4 [expr.new]
8- new表达式通过调用分配函数(3.7.4.1)为对象获取存储空间。如果new表达式由于抛出异常而终止,它可能通过调用解分配函数(3.7.4.2)释放存储空间。如果分配的类型是非数组类型,则分配函数的名称为operator new,解分配函数的名称为operator delete。如果分配的类型是数组类型,则分配函数的名称为operator new[],解分配函数的名称为operator delete[]。
18- 如果上述任何对象初始化的一部分76由于抛出异常而终止,并且可以找到一个合适的解分配函数,则在构造对象的内存中释放该内存的解分配函数被调用,此后异常将在new表达式的上下文中继续传播。如果找不到明确匹配的解分配函数,则传播异常不会导致对象的内存被释放。[ 注意:当调用的分配函数不分配内存时,这是适当的;否则,它很可能导致内存泄漏。——注释结束 ]
换句话说,除非编译器找不到适当的解分配函数(例如,您弄乱了自定义(de)分配器或实际上不需要释放内存),否则内存将自动释放。

-1

请查看Scoot Meyers的书《More Effective C++》中的第10项。

该项中的一个重要引用是:

  • "C++仅销毁完全构造的对象,而对象直到其构造函数运行完成才算完全构造。"。因此,如果在构造函数中抛出异常并且没有在构造函数中捕获它,则析构函数将永远不会被调用。

对于具体的解决方案,我强烈建议您阅读这一项(或更好地阅读整本书)。


2
这如何回答分配的内存会发生什么事的问题? - jalf
我在类名中给出了一个线索:ThirdPartyClass。通常情况下,第三方的东西是不能被篡改的。但这并不意味着我们不应该对其发生故障时的情况进行保证。 - Craig

-2
这是一个很好的问题,正确的处理需要一篇完整的文章。好消息是有人已经写了这篇文章:构造函数失败。在类构造过程中,如果出现异常,分配的内存会发生什么情况,你该如何处理这种情况。

2
这不是关于构造函数如何工作的问题,而是关于new如何工作的问题。 - R. Martinho Fernandes
当一个类在构造过程中抛出异常时,分配的内存会发生什么情况? - Maxim Egorushkin
我不在乎你是否愿意阅读整个内容。这并不能使它更有帮助。 - R. Martinho Fernandes
@R.MartinhoFernandes,你假设构造函数没有定义的情况下不分配内存。 - Maxim Egorushkin
1
内存是由operator new分配的,而不是构造函数。很明显,为新实例分配的内存大小为sizeof(ThirdPartyClass),没有其他可能性。 - R. Martinho Fernandes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接