質問:Java / C#でRAIIを実装できないのはなぜですか?
明確化:ガベージコレクターは決定論的ではないことを認識しています。そのため、現在の言語機能では、オブジェクトのDispose()メソッドをスコープの終了時に自動的に呼び出すことはできません。しかし、そのような決定論的な機能を追加できますか?
私の理解:
RAIIの実装は、次の2つの要件を満たす必要があると感じてい
ます。1.リソースの有効期間はスコープにバインドされている必要があります。
2.暗黙的。リソースの解放は、プログラマーによる明示的なステートメントなしで行われる必要があります。明示的なステートメントなしでメモリを解放するガベージコレクターに似ています。「暗黙性」は、クラスの使用ポイントでのみ発生する必要があります。もちろん、クラスライブラリの作成者は、デストラクタまたはDispose()メソッドを明示的に実装する必要があります。
Java / C#はポイント1を満たします。C#では、IDisposableを実装するリソースを「using」スコープにバインドできます。
void test()
{
using(Resource r = new Resource())
{
r.foo();
}//resource released on scope exit
}
これはポイント2を満たしません。プログラマは、オブジェクトを特別な「使用」スコープに明示的に結び付けなければなりません。プログラマーは、リソースをスコープに明示的に結び付けることを忘れる可能性があり(実際にそうします)、リークを作成します。
実際、「使用中」ブロックは、コンパイラーによってtry-finally-dispose()コードに変換されます。try-finally-dispose()パターンと同じ明示的な性質を持っています。暗黙のリリースがなければ、スコープへのフックは構文糖衣です。
void test()
{
//Programmer forgot (or was not aware of the need) to explicitly
//bind Resource to a scope.
Resource r = new Resource();
r.foo();
}//resource leaked!!!
Java / C#で言語機能を作成して、スマートポインターを介してスタックにフックされる特別なオブジェクトを許可する価値があると思います。この機能を使用すると、クラスをスコープバインドとしてフラグ付けできるため、常にスタックへのフックを使用して作成されます。さまざまな種類のスマートポインターのオプションがあります。
class Resource - ScopeBound
{
/* class details */
void Dispose()
{
//free resource
}
}
void test()
{
//class Resource was flagged as ScopeBound so the tie to the stack is implicit.
Resource r = new Resource(); //r is a smart-pointer
r.foo();
}//resource released on scope exit.
暗黙性は「価値がある」と思います。ガベージコレクションの暗黙性が「価値がある」ように。明示的にブロックを使用することは目をリフレッシュしますが、try-finally-dispose()よりもセマンティックな利点はありません。
そのような機能をJava / C#言語に実装することは非実用的ですか?古いコードを壊さずに導入できますか?
using
の実行Dispose
が保証されていることに注意してください(まあ、例外がスローされることなく突然死んでしまうプロセスを割り引くと、その時点ですべてのクリーンアップはおそらく無意味になります)。
struct
Dispose
sがされ、これまでにかかわらず、それらがトリガーしているかの、実行します。スコープの終わりに暗黙的な破壊を追加しても、それは役に立ちません。