是在构造函数引发异常时调用的析构函数
本文关键字:调用 析构函数 异常 构造函数 | 更新日期: 2023-09-27 17:48:52
正在寻找C#和C++的答案。(在C#中,将"析构函数"替换为"终结器")
它适用于C#(请参阅下面的代码),但不适用于C++。
using System;
class Test
{
Test()
{
throw new Exception();
}
~Test()
{
Console.WriteLine("Finalized");
}
static void Main()
{
try
{
new Test();
}
catch {}
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
这将打印"Finalized"
序言:Herb Sutter有一篇关于的伟大文章
http://herbsutter.wordpress.com/2008/07/25/constructor-exceptions-in-c-c-and-java/
C++:是和否
如果构造函数抛出(对象"从未存在"),则不会调用对象析构函数,但可以调用其内部对象的析构函数。
总之,对象的每个内部部分(即成员对象)都将以与其构造相反的顺序调用其析构函数。除非以某种方式使用RAII,否则构造函数中构建的每一个东西都不会调用其析构函数。
例如:
struct Class
{
Class() ;
~Class() ;
Thing * m_pThing ;
Object m_aObject ;
Gizmo * m_pGizmo ;
Data m_aData ;
}
Class::Class()
{
this->m_pThing = new Thing() ;
this->m_pGizmo = new Gizmo() ;
}
创建顺序为:
- m_aObject将调用其构造函数
- m_aData将调用其构造函数
- 调用类构造函数
- 在类构造函数中,m_pThing将调用其新的然后调用构造函数
- 在类构造函数中,m_pGizmo将调用它的新构造函数,然后调用构造函数
假设我们使用以下代码:
Class pClass = new Class() ;
一些可能的情况:
如果m_aData在构造时抛出,m_aObject将调用其析构函数。然后,由";新类别";已解除分配。
如果m_pThing抛出新的Thing(内存不足),m_aData,然后m_aObject将调用它们的析构函数。然后,由新类分配的内存被释放。
如果m_pThing在构造时抛出;"新事物";将被解除分配。然后m_aData和m_aObject将调用它们的析构函数。然后,由新类分配的内存被释放。
如果m_pGizmo在构造时抛出;新Gizmo";将被解除分配。然后m_aData和m_aObject将调用它们的析构函数。然后,由新类分配的内存被释放注意m_pThing泄漏
如果你想提供基本的异常保证,你不能泄漏,即使在构造函数中。因此,您必须这样写(使用STL,甚至Boost):
struct Class
{
Class() ;
~Class() ;
std::auto_ptr<Thing> m_pThing ;
Object m_aObject ;
std::auto_ptr<Gizmo> m_pGizmo ;
Data m_aData ;
}
Class::Class()
: m_pThing(new Thing())
, m_pGizmo(new Gizmo())
{
}
甚至:
Class::Class()
{
this->m_pThing.reset(new Thing()) ;
this->m_pGizmo.reset(new Gizmo()) ;
}
如果您希望/需要在构造函数中创建这些对象。
这样,无论构造函数抛出到哪里,都不会泄露任何内容。
仍在构造的类的析构函数不会被调用,因为对象从未完全构造好。
然而,它的基类(如果有的话)的析构函数被调用了,因为该对象是作为基类对象构造的。
此外,任何成员变量都会调用其析构函数(正如其他人所指出的)。
注意:这适用于C++
在C++中,答案是no-对象的析构函数被不调用。
但是,对象上任何成员数据的析构函数都将被调用,除非在构造其中一个时抛出异常。
C++中的成员数据以与声明相同的顺序初始化(即构造),因此当构造函数抛出时,所有已初始化的成员数据(无论是在成员初始化列表(MIL)中还是在其他情况下)都将以相反的顺序再次被拆下。
如果构造函数没有完成执行,那么对象就不存在,因此没有什么可销毁的。这是在C++中,我对C#一无所知。
对于C++,这在前面的问题中得到了解决:下面的代码会导致C++中的内存泄漏吗
由于在C++中,当在构造函数中抛出异常时,析构函数不会被调用,但对象成员(已构造)的dtor会被调用,这是使用智能指针对象而不是原始指针的主要原因-在这种情况下,它们是防止内存泄漏的好方法。
C++-
没有。不为部分构造的对象调用析构函数。洞穴:析构函数将为其完全构建的成员对象调用。(包括自动对象和本机类型)
BTW-您真正想要的是所谓的"堆栈放卷"
不要在构造函数中做导致异常的事情。
在可以引发异常的构造函数之后调用Initialize()。