いつデストラクタを作成する必要がありますか?


185

例えば:

public class Person
{
    public Person()
    {
    }

    ~Person()
    {
    }
}

いつデストラクタを手動で作成する必要がありますか?デストラクタを作成する必要があるのはいつですか?


1
C#言語ではこれらを「デストラクタ」と呼んでいますが、ほとんどの人は「ファイナライザ」と呼んでいます。これは、その.NET名であり、C ++デストラクタ(まったく異なる)との混同を減らすためです。IDisposableおよびFinalizerを実装する方法:3つの簡単なルール
Stephen Cleary

5
無謀な気持ちになったとき。
capdragon

32
TomTomのキーボードが誤動作していたと思います。Caps Lockは散発的にオンとオフを繰り返していました。変だ。
Jeff LaFay、2011


私はグレッグブナの提案に基づいて、デバッグ支援として、デストラクタを使用して終了:stackoverflow.com/questions/3832911/...
ブライアン・

回答:


237

更新:この質問は、2015年5月の私のブログの主題でした。すばらしい質問をありがとう!人々がファイナライズについて一般的に信じている虚偽の長いリストについては、ブログを参照してください。

いつデストラクタを手動で作成する必要がありますか?

ほとんどは決してない。

通常、クラスがデストラクタを作成するのは、オブジェクトが削除されたときにクリーンアップする必要がある高価なアンマネージリソースをクラスが保持している場合のみです。リソースを確実にクリーンアップするには、使い捨てパターンを使用することをお勧めします。デストラクタは、本質的には、オブジェクトのコンシューマーが破棄を忘れた場合でも、リソースが最終的にクリーンアップされることを保証するものです。(多分。)

デストラクタを作成する場合は、非常に注意深く、ガベージコレクタの動作理解してください。デストラクタは本当に奇妙です:

  • 彼らはあなたのスレッドで実行されません。彼らは自分のスレッドで実行されます。デッドロックを引き起こさないでください!
  • デストラクタからスローされた未処理の例外は悪い知らせです。独自のスレッド上にあります。誰が捕まえるの?
  • デストラクタは、コンストラクタが開始した、コンストラクタが終了する前にオブジェクトで呼び出すことができます。適切に記述されたデストラクタは、コンストラクタで確立された不変式に依存しません。
  • デストラクタはオブジェクトを「復活」させて、死んだオブジェクトを再び生き返らせることができます。それは本当に奇妙です。しないでください。
  • デストラクタが実行されることはありません。ファイナライズがスケジュールされているオブジェクトに依存することはできません。それはおそらくになりますが、それは保証ではありません。

デストラクタでは、通常正しいことはほとんどありません。本当に、本当に注意してください。正しいデストラクタを作成することは非常に困難です。

デストラクタを作成する必要があるのはいつですか?

デストラクタを処理するコンパイラの部分をテストするとき。量産コードでこれを行う必要はありませんでした。アンマネージリソースを操作するオブジェクトを作成することはほとんどありません。


「コンストラクターが開始した後、コンストラクターが完了する前に、オブジェクトでデストラクタが呼び出される可能性があります。」しかし、フィールドイニシャライザに依存して実行できますよね。
コンフィギュレー

13
@configurator:いいえ。例外がスローされる原因となった静的メソッドと呼ばれるファイナライザを持つオブジェクトの3番目のフィールド初期化子を想定します。4番目のフィールド初期化子はいつ実行されますか?決して。ただし、オブジェクトはまだ割り当てられており、ファイナライズする必要があります。一体、dtorの実行時にdouble型のフィールドが完全に初期化されたという保証さえありません。doubleの書き込みの途中でスレッドが中止された可能性があり、ファイナライザは半分初期化されたhalf-zero doubleを処理する必要があります。
Eric Lippert、2011年

1
優れた投稿ですが、「クラスがいくつかの高価なアンマネージオブジェクトを保持している場合、または多数のアンマネージオブジェクトが存在する場合に作成する必要があります」-具体的な例として、基になるネイティブC ++を利用するC#のマトリックスクラスがあります重い物を持ち上げるの多くを行うための行列クラス-私は行列の多くを作る-それは、より良い同期に家の管理とアンマネージ側面を保持しますので、「デストラクタ」は、この特定のケースではIDisposableをよりはるかに優れている
マーク・マリン

1
pythonnetはデストラクタを使用して、アンマネージCPythonでGILをリリースします
denfromufa '26 / 08/26

3
素晴らしい記事エリック。このための小道具-> "追加ボーナスの楽しみ:デバッガーでプログラムを実行するとき、ランタイムはあまり積極的ではないコード生成とそれほど積極的ではないガベージコレクションを使用します。オブジェクトを参照する変数はスコープ内にあります。つまり、オブジェクトが早期にファイナライズされているバグがある場合、デバッガでそのバグを再現できない可能性があります。」
Ken Palmer

17

これは「ファイナライザ」と呼ばれ、通常、状態(つまり:フィールド)にアンマネージリソース(つまり、p / invoke呼び出しで取得されたハンドルへのポインタ)が含まれるクラスに対してのみ作成する必要があります。ただし、.NET 2.0以降では、実際にはアンマネージリソースのクリーンアップを処理するためのより良い方法があります。それはSafeHandleです。このため、ファイナライザを再度作成する必要はほとんどありません。


25
@ThomasEding- はい、そうです。C#はデストラクタ構文を使用しますが、実際にはファイナライザーを作成しています。もう一度
JDBは

@JDB:言語構造はデストラクタと呼ばれます。名前は嫌いですが、それがその名前です。デストラクタを宣言することにより、コンパイラはファイナライザメソッドを生成します。ファイナライザメソッドには、デストラクタの本体に表示されるものとともに、ラッパーコードが少し含まれています。
スーパーキャット

8

クラスがWindowsファイルハンドルなどのアンマネージリソースを維持している場合を除き、必要はありません。


5
まあ、実際には、それはデストラクタと呼ばれています
デビッド

2
今、私は混乱しています。それはファイナライザですか、それともデストラクタですか?

4
C#仕様では、実際にそれをデストラクタと呼んでいます。これを間違いだと考える人もいます。stackoverflow.com/questions/1872700/...
アニ

2
@ThomasEding- はい、そうです。C#はデストラクタ構文を使用しますが、実際にはファイナライザーを作成しています。
JDBは2012

2
私はここのコメントが大好きです、本物のパント:)
Benjol

4

これはデストラクタ/ファイナライザと呼ばれ、通常、Disposedパターンを実装するときに作成されます。

これは、クラスのユーザーがDisposeの呼び出しを忘れた場合のフォールバックソリューションであり、(最終的に)リソースが解放されることを確認しますが、デストラクターがいつ呼び出されるかについては保証されません。

このスタックオーバーフローの質問で、受け入れられた回答は、破棄パターンを実装する方法を正しく示しています。これは、ガベージコレクターが自分自身をクリーンアップするために管理できない、処理されないリソースがクラスに含まれている場合にのみ必要です。

ファイナライザを実装せずに、クラスのユーザーに手動でオブジェクトを破棄してリソースをすぐに解放できるようにすることをお勧めします。


実際には、それはC#ではデストラクタと呼ばれていません。
TomTom、2011

14
実際です。あなたが間違っているので私に反対票を与えてくれてありがとう。この特定の問題について、MSDNライブラリを参照してください。msdn.microsoft.com/en-us/library/66x5fx1b.aspx
ØyvindBråthen

1
@TomTom正式名称はデストラクタです
デビッド

実際にはフォールバックメソッドではなく、オブジェクトがアンマネージリソースを解放したときにGCが管理できるようにするだけです。IDisposableを実装すると、自分で管理できます。
HasaniH

3

アンマネージリソースがあり、オブジェクトが削除されたときにそれらが確実にクリーンアップされるようにする必要がある場合。良い例は、COMオブジェクトまたはファイルハンドラです。


2

デストラクタを使用して(デバッグ目的でのみ)、オブジェクトがWPFアプリケーションのスコープ内のメモリから削除されているかどうかを確認しました。ガベージコレクションが本当にオブジェクトをメモリから削除しているかどうかはわかりませんでしたが、これは検証に適した方法でした。


1

デストラクタは、クラスにカプセル化されたアンマネージリソースを暗黙的に解放する方法を提供します。デストラクタは、GCがそれに到達すると呼び出され、基本クラスのFinalizeメソッドを暗黙的に呼び出します。アンマネージリソースを多数使用している場合は、IDisposableインターフェイスを介してそれらのリソースを解放する明示的な方法を提供することをお勧めします。C#プログラミングガイドを参照してくださいhttp : //msdn.microsoft.com/en-us/library/66x5fx1b.aspx

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.