http://www.blogcn.com/user8/flier_lu/index.html?id=1485755&run=.08F07F8
上周Lippman在其Blog上发表了一篇介绍新版本Managed C++中析构函数语义变化的文章:Changes in Destructor Semantics in Support of Deterministic Finalization。
我们知道在C#和Managed C++中,析构函数实际上被编译器翻译成对Object.Finalize函数的重载。例如在Managed C++中定义如下的类
以下为引用:
__gc class A
{
public:
~A() { Console::WriteLine(S"in ~A"); }
};__gc class B : public A
{
public:
~B() { Console::WriteLine(S"in ~B"); }
};
在Managed C++的实现上被编译器自动转换成
以下为引用:
// internal transformation of destructor under V1
__gc class A
{
public:
void Finalize() { Console::WriteLine(S"in ~A"); }
};__gc class B : public A
{
public:
void Finalize()
{
Console::WriteLine(S"in ~B");A::Finalize();
}
};
但为了语义上兼容C++的程序,Managed C++同时也提供了一个虚方法实现析构函数。
以下为引用:
__gc class A
{
public:
virtual ~A()
{
System::GC::SuppressFinalize(this);A::Finalize();
}
};__gc class B : public A
{
public:
virtual ~B()
{
System::GC:SuppressFinalize(this);B::Finalize();
}
};
这样一来就允许Managed C++用户显式地调用类的Finalize()函数。
虽然这样的思路在目前CLR版本中可以正常运转,但实际上和Dispose模式存在重合和冲突的地方,而且频繁使用Finalizer也会导致效率的降低。因此在新版本的Managed C++中,析构函数改为使用Dispose模式来实现。上面的代码被编译器自动转换为
以下为引用:
// internal transformation of destructor under V2
__gc class A : IDisposable
{
public:
void Dispose()
{
System::GC::SuppressFinalize(this);Console::WriteLine( "in ~A"); }
}
};__gc class B : public A
{
public:
void Dispose()
{
System::GC::SuppressFinalize(this);Console::WriteLine( "in ~B");
A::Dispose();
}
};
而对此类进行的析构操作,无论是直接调用类的析构函数,还是通过delete关键字隐式调用,都会被编译器翻译成对Dispose方法的调用。
但这样一来GC就无法访问类的析构代码了,因为析构函数没有直接被转换成Finalize函数。为此Managed C++新版本提供了一个修订语法,通过''!''前缀支持显式定义Finalize函数,例如:
以下为引用:
public ref class R
{
public:
!R() { Console::WriteLine( "I am the R::finalizer()!" ); }
};
被新版本Managed C++编译器自动转换为
以下为引用:
// internal transformation under V2
public ref class R
{
public:
void Finalize() { Console::WriteLine( "I am the R::finalizer()!" ); }
};
为了支持从老版本的Managed C++中将代码移植出来,MS还准备开发一个自动转换工具,将原本显式定义的Dispose()方法转换为析构函数;将原本定义的析构函数转换为!前缀支持的显式Finalize函数定义。
有趣的是,这一实现思路与Delphi.NET完成类似析构函数语义的思路很相似,有兴趣进一步了解的朋友可以参考这篇文章
Object Destructors and Finalizers in .NET Using C# and Delphi for .NET
几位Borland系统的老兄也针对相关问题有一些不错的评论: