既に推測したように、はい、C ++はそのメカニズムなしで同じ機能を提供します。したがって、厳密に言えば、try
/ finally
メカニズムは実際には必要ありません。
とは言っても、それなしで行うと、残りの言語の設計方法にいくつかの要件が課せられます。C ++では、同じアクションのセットがクラスのデストラクタに組み込まれています。C ++でのデストラクタ呼び出しは決定論的であるため、これは主に(排他的に?)動作します。これは、オブジェクトのライフタイムに関するかなり複雑なルールにつながり、そのいくつかは明らかに直感的ではありません。
他のほとんどの言語は、代わりに何らかの形式のガベージコレクションを提供します。ガベージコレクションに関して物議を醸すもの(たとえば、他のメモリ管理方法と比較した場合の効率)がありますが、一般的にはそうではありません。オブジェクトのスコープに。これにより、正しい操作に単純に必要な場合や、クリーンアップがwhen意的に遅延しないほど貴重なリソースを処理する場合に、クリーンアップを決定論的に行う必要がある場合に使用できなくなります。try
/ finally
は、そのような言語がその決定論的なクリーンアップを必要とする状況に対処する方法を提供します。
この機能のC ++構文はJavaよりも「友好的ではない」と主張する人々は、むしろその点を失っていると思います。さらに悪いことに、彼らは、構文をはるかに超えた責任分担について、はるかに重要なポイントを見逃しており、コードの設計方法により多くのことが関係しています。
C ++では、この決定論的なクリーンアップはオブジェクトのデストラクタで行われます。つまり、オブジェクトはそれ自体をクリーンアップするように設計できます(通常は設計する必要があります)。これは、オブジェクト指向設計の本質です。クラスは、抽象化を提供し、独自の不変条件を強制するように設計する必要があります。C ++では、それを正確に行います。オブジェクトが破棄されると、オブジェクトによって制御されるリソース(メモリだけでなく、すべて)が正しく破棄されるという不変条件の1つです。
Java(および同様の)は多少異なります。finalize
理論的には同様の機能を提供する可能性のある(種類の)サポートを提供しますが、サポートは非常に弱いため、基本的に使用できません(実際、使用されません)。
その結果、クラス自体が必要なクリーンアップを実行できるのではなく、クラスのクライアントがそうするための手順を実行する必要があります。十分に近視眼的な比較を行うと、一見するとこの違いはごくわずかであり、この点でJavaはC ++とかなり競争力があるように見えます。このような結果になります。C ++では、クラスは次のようになります。
class Foo {
// ...
public:
void do_whatever() { if (xyz) throw something; }
~Foo() { /* handle cleanup */ }
};
...クライアントコードは次のようになります。
void f() {
Foo f;
f.do_whatever();
// possibly more code that might throw here
}
Javaでは、クラス内でオブジェクトが少しだけ使用されるコードを少し交換します。これは当初、かなり均等なトレードオフのように見えます。しかし実際には、ほとんどの典型的なコードでは1か所でクラスを定義するだけで、多くの場所で使用しているため、そこからは程遠いものです。C ++アプローチとは、クリーンアップを1か所で処理するためのコードのみを記述することを意味します。Javaのアプローチとは、クリーンアップを何度も何度も処理するコードを記述する必要があることを意味します。あらゆる場所で、そのクラスのオブジェクトを使用するたびに。
要するに、Javaのアプローチは、基本的に、提供しようとする多くの抽象化が「漏れやすい」ことを保証します。決定論的なクリーンアップを必要とするすべてのクラスは、クラスのクライアントにクリーンアップの詳細とクリーンアップ方法を知る義務を負います、それらの詳細がクラス自体に隠されるのではなく。
上記では「Javaアプローチ」と呼んでいますが、try
/ finally
および他の名前の同様のメカニズムはJavaに完全に制限されているわけではありません。顕著な例の1つとして、ほとんどの(すべて?).NET言語(C#など)が同じものを提供しています。
JavaとC#の両方の最近の反復も、この点で「古典的な」JavaとC ++の中間点を提供します。C#では、クリーンアップを自動化するオブジェクトがIDisposable
インターフェイスを実装できます。これによりDispose
、C ++デストラクタに(少なくともあいまいに)似たメソッドが提供されます。これは Javaのtry
/のfinally
ように使用できますが、C#は、スコープに入ると作成され、スコープが出ると破棄されるリソースを定義できるステートメントを使用して、タスクをもう少し自動化しますusing
。C ++が提供する自動化と確実性のレベルにはまだ十分ではありませんが、これはJavaに対する大幅な改善です。特に、クラス設計者は、方法の詳細を集中化できます。の実装でクラスを破棄するIDisposable
。クライアントプログラマーに残されてusing
いるのは、IDisposable
インターフェースを使用する必要があるときに使用されることを保証するステートメントを記述する負担が少ないことです。Java 7以降では、有罪を保護するために名前が変更されていますが、基本的な考え方は基本的に同じです。