私は非決定論的破壊について混乱するのに忙しい。別の質問への回答で、デストラクタ/ファイナリザ(c#でも同じであると想定しています。つまり、〜classname()という関数)は高価であり、必須ではないというアドバイスを受けました。しかし、この例を見ると、デストラクタが使用されており、コメントからはそれが不可欠であるように思われます。これがどのように組み合わされるかについて誰かがアドバイスを受けました。コードからデストラクタを削除する必要がありますか?
再度、感謝します。
明示的に実行されているかどうかに関係なく、ある時点でどうしてもクリーンアップを実行する必要がある場合にのみ、ファイナライザーを含める必要があります。このような場合は、とにかくタイムリーにクリーンアップを実行する明示的な方法を常に用意する必要があります。これにより、とにかくファイナライズを抑制して、「優れた」クライアントにパフォーマンスの低下が見られないようにする必要があります。
通常、ファイナライザーが必要になるのは、アンマネージリソースへの直接ハンドルがある場合のみです。リソース(たとえば)をハンドルする別のFileStream
クラスへの参照しかない場合は、ファイナライザーを取得するために他のクラスに任せる必要があります。
.NET 2.0の登場により、SafeHandle
独自のファイナライザーを作成する価値のある状況は実際には非常にまれです。
ファイナライザーのパフォーマンス上のペナルティは、オブジェクトが必要以上に長く存続することです。それ以外の場合は収集の対象と見なされる最初のGCサイクルで、ファイナライザーキューに入れられ、次の世代にバンプされます。 GCサイクルを生き残る他のオブジェクトのように。その後、ファイナライザーは別のスレッドで実行され(ある時点で)、実際に収集される資格があります。したがって、(たとえば)最初のgen1コレクションに収集される代わりに、次のgen2コレクションまでそれを超えて生きます。これはかなり後になる可能性があります。
通常、デストラクタを実装すると、次の場合に役立ちます。保証されていない場合、クライアントコードはすべてのリソース(ファイルストリーム、データベース接続など)を適切に閉じます。したがって、クライアントコードで失敗した場合は、コードを閉じて閉じます。これは、リソースを開いたままにしておくよりも優れています。
アンマネージド リソースを直接処理する場合は、完全な Disposable パターンのみが必要です。そして、デストラクタが (ほとんど) 使用されないようにするのは、呼び出し元のコード次第です。
管理されたリソース (= 管理されていないリソースの間接的な所有権) を扱う場合、デストラクタは役に立ちません:
class FileWrapper
{
private FileStream fs; // managed resource
~FileWrapper()
{
if (fs != null)
fs.Dispose(); // fs is already on the GC finalizer queue
}
}
FileWrapper オブジェクトが GC によって収集されているときはいつでも、fs オブジェクトが同じバッチにあることは確実です。したがって、fs.Dispose() の呼び出しは役に立たず、FileStream.Dispose() の正しい (複数の呼び出しを許可する) 動作をテストするだけです。
ここで有用なデストラクタは、FileStream のものだけです。