为什么GC不会自动处理我班级的成员?

时间:2009-08-12 12:50:33

标签: garbage-collection c++-cli code-analysis idisposable ca1001

当我在VS2008中构建以下C ++ / CLI代码时,会显示代码分析警告CA1001。

ref class A
{
public:
    A()   { m_hwnd = new HWND; }
    ~A()  { this->!A(); }
protected:
    !A()  { delete m_hwnd; }
    HWND* m_hwnd;
};

ref class B
{
public:
    B()   { m_a = gcnew A(); }
protected:
    A^    m_a;
};
  

警告:CA1001:Microsoft.Design:   在'B'上实现IDisposable因为   它创建了以下成员   IDisisable类型:'A'。

要解决此警告,我必须将此代码添加到B类:

    ~B()  { delete m_a; }

但我不明白为什么。 A类通过其析构函数(和终结器)实现IDisposable 所以当A被垃圾收集时,A的终结器或析构函数将被调用,从而释放其非托管资源。

为什么B必须在其A成员上添加析构函数来调用'delete'? 如果B显式调用“delete m_a”,那么GC是否只调用A的析构函数?


编辑:如果您使用声明A成员的“syntax sugar”方法,它似乎会自动生效,如下所示:

ref class B
{
public:
    B()   { }
protected:
    A     m_a;
};

但这并非总是可行。

为什么GC没有足够聪明地自动处理A ^的托管引用指针,一旦没有其他人有指向它的指针?

1 个答案:

答案 0 :(得分:2)

您应该为成员使用堆栈语义,并将析构函数添加到包含的类中。 然后该成员将被处置。 见http://msdn.microsoft.com/en-us/library/ms177197.aspx

ref class B
{
public:
    B()   {}
    ~B()  {}
protected:
    A    m_a;
};

该成员仍然是裁判。输入并仍然在堆上创建。

编辑:

在.net中处理充其量是不幸的,在C#中,整个确定性行为都被打破了,你必须对Dispose调用非常危险,以获得大多数c ++开发人员所期望的行为。

在c ++ / cli中,堆栈语义使它更好。如果你不能使用它们,你就必须明确地调用dispose,它在c ++ / cli中由析构函数表示。

自动链接调用成员的唯一方法是通过堆栈语义,如果成员是普通的托管指针,就像c#一样,你必须手动链接调用。

许多类可以保存相同的A ^指针,无法知道哪一个应该调用析构函数。

您收到警告,因为您已经实现了析构函数,这会导致您的类实现IDispose。这使您有机会以确定的方式进行清理。

GC单独只能收集没有引用的对象并调用终结器。这远非确定性的。请注意,依靠终结器进行清理应该是一个安全网,因为它可能会在将来被称为很长时间。

我建议您尝试设计代码以允许上述模式。