C# 如果构造函数引发异常,是否调用析构函数? 寻找C和C++的答案。(在C中,用‘终结器’替换‘析构函数’)
它对C++是(参见下面的代码),而不是C++()。C# 如果构造函数引发异常,是否调用析构函数? 寻找C和C++的答案。(在C中,用‘终结器’替换‘析构函数’),c#,c++,destructor,finalizer,C#,C++,Destructor,Finalizer,它对C++是(参见下面的代码),而不是C++()。 using System; class Test { Test() { throw new Exception(); } ~Test() { Console.WriteLine("Finalized"); } static void Main() { try { new Test();
using System;
class Test
{
Test()
{
throw new Exception();
}
~Test()
{
Console.WriteLine("Finalized");
}
static void Main()
{
try
{
new Test();
}
catch {}
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
这将打印“已完成”如果构造函数没有完成执行,则对象不存在,因此没有要销毁的内容。这是C++中的,我对C++的概念没有了解。< P>C++-< 没有。对于部分构造的对象,不调用析构函数。警告:对于完全构造的成员对象,将调用析构函数。(包括自动对象和本机类型)
BTW——你真正想要的是C++中的“栈退绕”< /p> ,答案是“不”对象的析构函数不被调用。
但是,将调用对象上任何成员数据的析构函数,除非在构造其中一个时引发异常在可以引发异常的构造函数之后调用Initialize()。序言:Herb Sutter有一篇关于该主题的精彩文章: 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() ;
}
创建顺序为:
Class pClass = new Class() ;
一些可能的情况:
- 如果m_aData抛出构造,m_AOObject将调用其析构函数。然后,释放“新类”分配的内存
- 如果m_pThing抛出新事物(内存不足),m_aData,那么m_aObject将调用它们的析构函数。然后,释放新类分配的内存
- 如果m_pThing抛出构造,则“新事物”分配的内存将被释放。然后m_aData,然后m_aObject将调用它们的析构函数。然后,释放新类分配的内存
- 如果m_pGizmo抛出构造,则“新Gizmo”分配的内存将被释放。然后m_aData,然后m_aObject将调用它们的析构函数。然后,释放新类分配的内存注意,m_pThing泄漏了
这样,无论构造函数抛出到哪里,都不会泄漏任何内容。不会调用仍在构造的类的析构函数,因为对象从未完全构造过 但是,将调用其基类(如果有)的析构函数,因为对象的构造方式与基类对象一样 此外,任何成员变量也将调用其析构函数(正如其他人所指出的)
NB:这适用于C++的<+/p>
C++,这在前面的问题中得到解决:
在C++中,当构造函数中抛出异常时,不调用析构函数,但调用对象成员(已构建)的DROR会被调用,这是在原始指针上使用智能指针对象的一个主要原因-在这种情况下,它们是防止内存泄漏的一个好方法。我认为这里要做的事情是设置一个一次性项目(或两个:每个语言一个)并进行检查。从命令行编译的乐趣在于不需要设置项目。只需在一个文本编辑器中加载一个文件,编译就非常容易,并且运行:)@ LueC等,C++和C语言的语义有很大的不同。这是两个独立的问题。对于C++,这可能是正确的,但不是C++。我认为测试是C语言中的终结器,而不是析构函数。啊,我知道~语法是设置终结器的糖分。在我的ctor可能抛出的情况下,我希望手动添加终结器作为ctor的最后一步,以避免清理不存在的混乱。@Logan:这取决于您阅读的C#spec的哪个版本,他们称它为“终结器”还是“析构函数”。@Jon:除了Ecma-334,还有其他C#specification吗?我知道它们是存在的,事实上它们是在你的网站上发布的。。。太糟糕了,2.0以上的版本没有标准规范。那就是说(抗议)。。。C语言终结器的语义不像C++析构函数(很明显,你知道)。在C#示例中,我认为用终结器代替处理器更合适。@FernandoPelliccioni:不,没有比这更高版本的ECMA规范了。至于处置——这个问题专门询问终结器。将其更改为使用Disposition不会回答这个问题。实际上,我正在编写STL样式的集合,所以我手动调用构造函数和析构函数。因此,我想知道在发生异常时调用析构函数是否正常。但是你描述的这个“部分破坏”必须由编译器完成,所以我不必。请你解释一下为什么?
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()) ;
}