37

注意: この質問は、「デストラクタ」と「ファイナライザ」という言葉の用語の違いと、それらの正しい使用法に関するものです。C# および C++/CLI での使用例を示して、なぜこの質問をするのかを示しただけです。C# と CLR の両方でどのように実装されているかはよく知っていますが、用語の正しい使い方について質問しています。


C# の世界では、「デストラクタ」と「ファイナライザ」という用語はほぼ同じ意味で使用されているように思われます。これは、C# の仕様では「デストラクタ」という言葉を使用して非決定論的クリーンアップ機能が記述されているためだと思われますが、CLR のドキュメントでは常に「ファイナライザー」という言葉なので、C# の領域内では同じことを意味します。

ただし、C++/CLI 仕様では、この 2 つが区別されています。決定論的および非決定論的なクリーンアップの両方が可能であり、決定論的な機能には「デストラクタ」という用語を使用し、非決定論的な機能には「ファイナライザ」という用語を使用します。

ファイナライザーは、非決定的なクリーンアップを提供します。ファイナライザは、通常、デストラクタが実行されなかったオブジェクトに対して、ガベージ コレクション中に実行される「ラストチャンス」関数です。

さらに、ウィキペディアのデストラクタとファイナライザの説明は、デストラクタファイナライザが別の概念であることを示しており、決定論に関する C++/CLI 仕様の用語の使用をサポートしています。

デストラクタとは異なり、ファイナライザは決定論的ではありません。プログラムがオブジェクトを明示的に解放すると、デストラクタが実行されます。対照的に、ファイナライザーは、内部ガベージ コレクション システムがオブジェクトを解放するときに実行されます。

質問:

  • コンピュータサイエンスの観点から、「デストラクタ」と「ファイナライザ」の間に明確に定義された違いはありますか、それとも用語は文脈上でのみ定義できるものですか?

  • 明確に定義された違いがある場合、なぜ C# 仕様は「間違った」用語を使用するのでしょうか?

4

4 に答える 4

40

1) 産業界や学界で使用されている「デストラクタ」と「ファイナライザ」の間に明確な違いはありますか?

確かにありそうです。違いは、デストラクタが決定論的に呼び出されるクリーンアップ メソッドであるのに対し、ファイナライザはガベージ コレクタが指示したときに実行されることです。

2) その場合、C# の仕様が間違っています。ファイナライザーは C# では「デストラクタ」と呼ばれます。なぜ C# 仕様の作成者はそれを間違えたのですか?

わかりませんが、推測できます。実は、私には2つの推測があります。

推測 #1 は、1999 年 5 月 12 日の時点で、これら 2 つの概念の微妙な違いを明確に説明しているウィキペディアの記事がなかったということです。ウィキペディアがなかったからです。ウィキペディアがなかった頃のことを覚えていますか? 暗黒時代、男。この誤りは、2 つの用語が同一であると信じていた単純な正直な間違いであった可能性があります。

私が知っている限りでは、1999 年 5 月 12 日の時点ではこの 2 つの用語同一であり、定義の違いは後になってようやく明らかになりました。熱心なクリーンアップ方法と怠惰なクリーンアップ方法を区別する必要があることが明らかになったからです。

推測 #2 は、1999 年 5 月 12 日に、言語設計委員会が「デストラクタ」をファイナライザ以外のものとして実装できる可能性を残したいと考えたことです。つまり、「デストラクタ」は、必ずしも .NET の「ファイナライザ」の概念と 1 対 1 で対応しない C# 言語の概念として設計されました。言語を設計すると同時に、その上にあるフレームワークも設計されている場合、サブシステムの最新の設計変更から身を守りたい場合があります。

1999 年 5 月 12 日の言語委員会のメモの一部は次のとおりです。

インスタンスが再利用されるときに実行されるメンバーに対して、「デストラクタ」という用語を使用します。クラスはデストラクタを持つことができます。構造体はできません。C++ とは異なり、デストラクタを明示的に呼び出すことはできません。破壊は非決定論的です。オブジェクトへのすべての参照が解放された後のある時点で実行されることを除いて、デストラクタがいつ実行されるかを確実に知ることはできません。継承チェーンのデストラクタは、最も子孫の多いものから最も少ない子孫の順に呼び出されます。派生クラスが基本デストラクタを明示的に呼び出す必要はありません (そしてその方法もありません)。C# コンパイラは、デストラクタを適切な CLR 表現にコンパイルします。このバージョンでは、おそらくメタデータで区別されるインスタンス ファイナライザーを意味します。CLR は将来、静的ファイナライザーを提供する可能性があります。静的ファイナライザーを使用する C# に対する障壁は見られません。

では、この件に関して私が知っていることはすべておわかりでしょう。詳しく知りたい場合は、次にアンダースに会ったときに尋ねてください。

于 2009-12-09T16:40:44.253 に答える
6

厳密に言えば、C# にはデストラクタがありません (C# の仕様はこの点で混乱していると思います)。C# のファイナライザは C++ デストラクタのように見えますが、おっしゃる通り非決定的です。C# には、次の形式の確定的なクリーンアップがありますIDisposable::Dispose(ただし、これはまだデストラクタとは呼ばれていません)。

C++/CLI には、C++ デストラクタに似た決定論的デストラクタがあります。CLI レベルでは、これらはIDisposable::Dispose()(IDisposableが実装されています ) にマップされます。C++/CLI には、デストラクタのように見えますが、! ^ プレフィックスの代わりにプレフィックス。

C++/CLI が、C# がファイナライザーに使用するのと同じ構文をデストラクタに使用するという事実は、少し混乱を招く可能性がありますが、決定論的破壊の強い伝統を持つ C++ により適しています。

残念ながら、これらの用語には普遍的な定義がないため、何について話しているのかを常に明確にする必要があります。個人的には、C# の概念について話すときは常にファイナライザーという言葉を使用し、確実に決定論的破壊を意味するコンテキストではデストラクタを予約しています。

[更新] ここでの最初の投稿以降、Eric Lippert は彼の応答 (受け入れられた回答) を投稿し、同じブログ投稿でフォローアップしました。意見が一致してうれしいです:-)

于 2009-12-09T09:48:13.693 に答える
4

「デストラクタ」は C# コードで、「ファイナライザ」はコンパイルされた CIL メソッドだと思います。C# コンパイラは、デストラクタをファイナライザに変換します。

編集:より冗長にするために。C# 言語仕様では、「デストラクタ」をクラスの C# インスタンス メソッドとして定義しています。したがって、「デストラクタ」は C# 文法の一部です。デストラクタは、ソース コードに現れる言語オブジェクトです。

デストラクタは、クラスのインスタンスを破棄するために必要なアクションを実装するメンバーです。デストラクタはパラメータを持つことも、アクセシビリティ修飾子を持つことも、明示的に呼び出すこともできません。インスタンスのデストラクタは、ガベージ コレクション中に自動的に呼び出されます。

「ファイナライザ」は、たとえば の呼び出しなど、共通言語ランタイムで使用される用語であり、GC.WaitForPendingFinalizers()C# だけでなく、任意の .net 言語を指します。任意の .net 参照型にファイナライザーを含めることができます。C# クラス (ソース コード アーティファクト) の場合、デストラクターは、CLR 型のファイナライザーである CIL メソッドにコンパイルされます。

またはもっと簡潔に言えば、ソースコードマシンコードになるように、デストラクタファイナライザになります;)

于 2009-12-09T09:43:39.217 に答える
3

デストラクタの「決定論的」定義を順守する場合、IDisposable インターフェイスを使用して明示的に実装しない限り、.NET オブジェクトにはデストラクタがないと言えます。

于 2009-12-09T09:46:52.880 に答える