C# 如果构造函数抛出异常,是否调用析构函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/188693/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is the destructor called if the constructor throws an exception?
提问by Qwertie
Looking for an answer for C# and C++. (in C#, replace 'destructor' with 'finalizer')
寻找 C# 和 C++ 的答案。(在 C# 中,将“析构函数”替换为“终结器”)
采纳答案by paercebal
Preamble: Herb Sutter has a great article on the subject:
序言:Herb Sutter 有一篇关于这个主题的精彩文章:
http://herbsutter.wordpress.com/2008/07/25/constructor-exceptions-in-c-c-and-java/
http://herbsutter.wordpress.com/2008/07/25/constructor-exceptions-in-cc-and-java/
C++ : Yes and No
C++:是和否
While an object destructor won't be called if its constructor throws (the object "never existed"), the destructors of its internal objects could be called.
如果对象的构造函数抛出异常(对象“从不存在”),则不会调用对象析构函数,但可以调用其内部对象的析构函数。
As a summary, every internal parts of the object (i.e. member objects) will have their destructors called in the reverse order of their construction. Every thing built inside the constructor won't have its destructor called unless RAII is used in some way.
总而言之,对象的每个内部部分(即成员对象)都将以其构造的相反顺序调用其析构函数。除非以某种方式使用 RAII,否则在构造函数中构建的每个事物都不会调用其析构函数。
For example:
例如:
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() ;
}
The order of creation will be:
创建顺序为:
- m_aObject will have its constructor called.
- m_aData will have its constructor called.
- Class constructor is called
- Inside Class constructor, m_pThing will have its new and then constructor called.
- Inside Class constructor, m_pGizmo will have its new and then constructor called.
- m_aObject 将调用其构造函数。
- m_aData 将调用其构造函数。
- 类构造函数被调用
- 在 Class 构造函数中, m_pThing 将调用其 new 然后构造函数。
- 在 Class 构造函数中, m_pGizmo 将调用其 new 然后构造函数。
Let's say we are using the following code:
假设我们正在使用以下代码:
Class pClass = new Class() ;
Some possible cases:
一些可能的情况:
Should m_aData throw at construction, m_aObject will have its destructor called. Then, the memory allocated by "new Class" is deallocated.
Should m_pThing throw at new Thing (out of memory), m_aData, and then m_aObject will have their destructors called. Then, the memory allocated by new Class is deallocated.
Should m_pThing throw at construction, the memory allocated by "new Thing" will be deallocated. Then m_aData, and then m_aObject will have their destructors called. Then, the memory allocated by new Class is deallocated.
Should m_pGizmo throw at construction, the memory allocated by "new Gizmo" will be deallocated. Then m_aData, and then m_aObject will have their destructors called. Then, the memory allocated by new Class is deallocated. Note that m_pThing leaked
如果 m_aData 在构造时抛出,则 m_aObject 将调用其析构函数。然后,“new Class”分配的内存被释放。
如果 m_pThing 抛出新事物(内存不足),m_aData,然后 m_aObject 将调用它们的析构函数。然后,new Class 分配的内存被释放。
如果 m_pThing 在构造时抛出,“new Thing”分配的内存将被释放。然后 m_aData 和 m_aObject 将调用它们的析构函数。然后,new Class 分配的内存被释放。
如果 m_pGizmo 在构造时抛出异常,“new Gizmo”分配的内存将被释放。然后 m_aData 和 m_aObject 将调用它们的析构函数。然后,new Class 分配的内存被释放。注意 m_pThing 泄露了
If you want to offer the Basic Exception Guarantee, you must not leak, even in the constructor. Thus, you'll have to write this this way (using STL, or even Boost):
如果你想提供基本异常保证,你不能泄漏,即使是在构造函数中。因此,你必须这样写(使用 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())
{
}
Or even:
甚至:
Class::Class()
{
this->m_pThing.reset(new Thing()) ;
this->m_pGizmo.reset(new Gizmo()) ;
}
if you want/need to create those objects inside the constructor.
如果您想/需要在构造函数中创建这些对象。
This way, no matter where the constructor throws, nothing will be leaked.
这样,无论构造函数在哪里抛出,都不会泄漏任何内容。
回答by Jon Skeet
It does for C# (see code below) but not for 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();
}
}
This prints "Finalized"
这将打印“已完成”
回答by Greg Rogers
If the constructor doesn't finish executing, the object doesn't exist, so there's nothing to destruct. This is in C++, I have no idea about C#.
如果构造函数没有完成执行,则对象不存在,因此没有什么可破坏的。这是在 C++ 中,我不知道 C#。
回答by Greg Rogers
C++ -
C++ -
Nope. Destructor is not called for partially constructed objects. A Caveat: The destructor will be called for its member objects which are completely constructed. (Includes automatic objects, and native types)
不。不为部分构造的对象调用析构函数。警告:析构函数将为其完全构造的成员对象调用。(包括自动对象和本机类型)
BTW - What you're really looking for is called "Stack Unwinding"
顺便说一句 - 你真正要找的是“堆栈展开”
回答by Matt Dillard
In C++, the answer is no - object's destructor is notcalled.
在 C++ 中,答案是否定的——不调用对象的析构函数。
However, the destructors of any member data on the object willbe called, unless the exception was thrown while constructing one of them.
然而,在对象上的任何成员数据的析构函数会被调用,除非在构造一个异常被抛出他们。
Member data in C++ is initialized (i.e. constructed) in the same order as it is declared, so when the constructor throws, all member data that has been initialized - either explicitly in the Member Initialization List (MIL) or otherwise - will be torn down again in reverse order.
C++ 中的成员数据的初始化(即构造)顺序与声明的顺序相同,因此当构造函数抛出时,所有已初始化的成员数据——无论是在成员初始化列表 (MIL) 中显式还是其他——都将被拆除再次以相反的顺序。
回答by Robert
Don't do things that cause exceptions in the constructor.
不要在构造函数中做导致异常的事情。
Call an Initialize() after the constructor that can throw exceptions.
在可以抛出异常的构造函数之后调用 Initialize()。
回答by MarkR
The destructor of the class still being constructed is not called, because the object was never fully constructed.
仍在构造的类的析构函数不会被调用,因为该对象从未完全构造过。
However, the destructor of its base class (if any) IS called, because the object was constructed as far as being a base class object.
然而,它的基类(如果有的话)的析构函数被调用,因为该对象被构造为一个基类对象。
Moreover, any member variables will have their destructors called too (as others have noted).
此外,任何成员变量也将调用其析构函数(正如其他人所指出的)。
NB: this applies to C++
注意:这适用于 C++
回答by Michael Burr
For C++ this is addressed in a previous question: Will the below code cause memory leak in c++
对于 C++,这在上一个问题中得到解决: Will the following code cause memory leak in c++
Since in C++ when an exception is thrown in a constructor the destructor does not get called, but dtors for the object's members (that have been constructed) do get called, this is a primary reason to use smart pointer objects over raw pointers - they are a good way to prevent memory leaks in a situation like this.
由于在 C++ 中,当在构造函数中抛出异常时,不会调用析构函数,但会调用对象成员(已构造)的 dtors,这是在原始指针上使用智能指针对象的主要原因 - 它们是在这种情况下防止内存泄漏的好方法。