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();
    }
}
这打印"已完成"
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() ;
}
创建顺序为:
假设我们使用以下代码:
Class pClass = new Class() ;
一些可能的情况:
如果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())
{
}
甚至:
Class::Class()
{
   this->m_pThing.reset(new Thing()) ;
   this->m_pGizmo.reset(new Gizmo()) ;
}
如果你想/需要在构造函数中创建这些对象.
这样,无论构造函数抛出何处,都不会泄露任何内容.
Mar*_*rkR 10
仍未构造的类的析构函数未被调用,因为该对象从未完全构造.
但是,它的基类(如果有的话)的析构函数被调用,因为该对象被构造为基类对象.
此外,任何成员变量也会调用它们的析构函数(正如其他人所指出的那样).
注意:这适用于C++
| 归档时间: | 
 | 
| 查看次数: | 11284 次 | 
| 最近记录: |