亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

C++CLIにおけるDisposeパターン

機能の記事ではC#でのDisposeパターンについて考察しました。そいでは現在僕がひぃひぃ言ってるC++CLIではどうなるのでしょうか。
以前の記事で書いたように、

つまり

C#のDispose → C++CLIのデストラクタ
C#のデストラクタ → C++CLIのファイナライザ
ということになるようです。

ということで、C++/CLIでのDisposeパターンは、MSDNによると以下のようになります。

// Visual C++ code
ref class T {
   ~T() { this->!T(); }   // Dispose = デストラクタ:~T()
   !T() {}   // デストラクタ= ファイナライザ:!T()
};

・・・あれ?ファイナイライザ呼び出しを抑制するSuppressFinalizeがありませんね。あるえ?C#だとDisposeに当たる場所、つまりデストラクタにファイナイライザ抑制コードが必要のはずです。
ということの答えは以下にあります。

新しい構文では、デストラクターの名前は内部で Dispose メソッドに変更され、参照クラスが自動的に拡張されて IDispose インターフェイスが実装されます。 したがって、先ほどのクラスのペアは、Visual C++ 2010 では次のように変換されます。

// internal transformation of destructor under the new syntax
__gc class A : IDisposable {
public:
   void Dispose() { 
      System::GC::SuppressFinalize(this);
      Console::WriteLine( "in ~A");
   }
};

なんということでしょう。
実はSyntaxSugarしてくれてたんですね。ポイントとしては、

  1. 勝手にIDisposableが実装される
  2. Disposeメソッドの中ではSupressFinalizeが呼ばれた後にデストラクタを呼び出す。

という2点でしょう。この機能により、

  1. デストラクタでマネージドなリソースを解放する
  2. ファイナライザでアンマネージドなリソースを解放する

を守っている限りにおいて、ほかのDisposeパターン実装はお任せできる、ということです。まぁもともとアンマネージドとマネージドをごっちゃ混ぜにすることが前提の言語ですから、これくらいのお助け機能は当然なのかもしれませんね。ともあれ勝手にやられることはちょっと気持ち悪いですが、仕様を覗けばやっぱりちょっとすっきりしますね。