Qwe*_*tie 42 c# c++ destructor finalizer
寻找C#和C++的答案.(在C#中,用'finalizer'替换'析构函数')
Jon*_*eet 54
它适用于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();
}
}
Run Code Online (Sandbox Code Playgroud)
这打印"已完成"
pae*_*bal 51
序言:Herb Sutter有一篇关于这个主题的精彩文章:
http://herbsutter.wordpress.com/2008/07/25/constructor-exceptions-in-cc-and-java/
虽然如果构造函数抛出(对象"从未存在"),将不会调用对象析构函数,但可以调用其内部对象的析构函数.
总而言之,对象的每个内部部分(即成员对象)将按其构造的相反顺序调用其析构函数.构造函数内部构建的每个东西都不会调用析构函数,除非以某种方式使用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() ;
}
Run Code Online (Sandbox Code Playgroud)
创建顺序为:
假设我们使用以下代码:
Class pClass = new Class() ;
Run Code Online (Sandbox Code Playgroud)
一些可能的情况:
如果m_aData在构造时抛出,m_aObject将调用其析构函数.然后,取消分配由"new Class"分配的内存.
如果m_pThing抛出新的Thing(内存不足),m_aData,然后m_aObject将调用它们的析构函数.然后,释放由新类分配的内存.
如果m_pThing在构造时抛出,则"new Thing"分配的内存将被释放.然后m_aData,然后m_aObject将调用它们的析构函数.然后,释放由新类分配的内存.
如果m_pGizmo在构造时抛出,"new 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())
{
}
Run Code Online (Sandbox Code Playgroud)
甚至:
Class::Class()
{
this->m_pThing.reset(new Thing()) ;
this->m_pGizmo.reset(new Gizmo()) ;
}
Run Code Online (Sandbox Code Playgroud)
如果你想/需要在构造函数中创建这些对象.
这样,无论构造函数抛出何处,都不会泄露任何内容.
Mar*_*rkR 10
仍未构造的类的析构函数未被调用,因为该对象从未完全构造.
但是,它的基类(如果有的话)的析构函数被调用,因为该对象被构造为基类对象.
此外,任何成员变量也会调用它们的析构函数(正如其他人所指出的那样).
注意:这适用于C++