Flier's Sky

天空,蓝色的天空,眼睛看不到的东西,眼睛看得到的东西

导航

修订版Managed C++中析构函数的语义更改

Posted on 2004-07-08 10:41  Flier Lu  阅读(773)  评论(0编辑  收藏  举报
修订版Managed C++中析构函数的语义更改

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系统的老兄也针对相关问题有一些不错的评论:

     Allen Bauer 的 The rules have not changed

     Nick Hodges 的 On Finalizers at Filafel