7

オブジェクト指向 Delphi のベスト プラクティスについて一般的な質問があります。現在、オブジェクトを作成するすべての場所に try-finally ブロックを配置して、使用後にそのオブジェクトを解放します (メモリ リークを回避するため)。例えば:

aObject := TObject.Create;
try
  aOBject.AProcedure();
  ...
finally
  aObject.Free;
end;

それ以外の:

aObject := TObject.Create;
aObject.AProcedure();
..
aObject.Free;

それは良い習慣だと思いますか、それともオーバーヘッドが多すぎると思いますか? そして、パフォーマンスはどうですか?

4

8 に答える 8

17

try-finally を使用することは間違いなくベスト プラクティスです。

例外が発生した場合、そのオブジェクト解放されます。

パフォーマンスに関しては、最適化する前に測定してください。

于 2010-05-27T16:40:00.260 に答える
15

私の意見では、オブジェクト構築の後にブロック が続くべきではない(または Mason が指摘したように「中」 )べきではない理由は 1 つだけです。try / finally

  1. オブジェクトの存続期間が別のオブジェクトによって管理されている場合。

この管理には、次の 3 つの形式があります。

  1. オブジェクトの参照には、ローカル ブロックを超えるスコープがあり、デストラクタで解放されたフィールド メンバーのように、他の場所で解放されます。
  2. 後でオブジェクトを解放することを担当するリストにすぐに追加されたオブジェクト。
  3. 作成時に所有者を VCL コントロールに渡す方法など、ライフタイム マネージャーが関連付けられたオブジェクト。

#1では、参照のスコープがより広い場合、参照がすぐに構築されない場合は、参照をすぐに nil に設定する必要があります。そうすれば、参照用にチェックされると、正確な読み取り値があることがわかります。これは、より大きなクラスの一部として構築され、親オブジェクトが破棄されたときにクリーンアップされるメンバー オブジェクトで最も一般的です。

#2では、オブジェクトが list に追加されるときに、オブジェクトが作成されて管理リストに追加される前に例外が発生した場合に備えて、try-exceptブロック (私が使用する数回のうちの 1 つ) を使用します。理想的には、構築後の最初の行がそれをリストに追加するか、リストは実際には、すでにリストに追加されているオブジェクトを提供するファクトリ クラスです。

#3では、オブジェクトに別のライフタイム マネージャーがある場合、そのマネージャーによって管理されることが正しいことを確認する必要があります。VCL コントロールを構築している場合、フォーム (または他のコントロール) にそれを所有させたくなるかもしれませんが、実際には、構築と破棄に追加のオーバーヘッドがかかります。可能であれば、明示的に解放する必要があります。これは、一度コントロールを配置した場合に特に当てはまります。その後、フォームのデストラクタで、またはフォームを閉じるときに解放することがわかっています。これができないのは、コントロールの作成がより動的な場合だけです。

そうです、多くのtry / finallyブロックを使用することがベストプラクティスです。いくつかのブロックのみを持つ必要がありtry / except、それらのほとんどすべてが非常に特定の例外タイプをトラップするか、例外を再発生させる必要があります。以上try / excepttry / finallyブロックがある場合は、間違っています

于 2010-05-27T20:48:19.457 に答える
13

フランクが言ったように、「パフォーマンスに関しては、最適化する前に測定してください」。強調するためにそれを繰り返します。

また、メソッドで多数のオブジェクトを作成する場合は、オブジェクトごとにtry..finallyブロックを使用する必要はありません。それは醜いインデントの混乱につながる可能性があります。create, try, create, try, create, try, do something, finally, free, finally, free, finally, free. うーん!代わりに、メソッドの先頭でオブジェクト参照をnilに設定し、それらをすべて作成し、 1つのtryブロックを実行して、finallyセクションですべてを解放することができます。

これにより、オーバーヘッドとパフォーマンスがいくらか節約されますが(おそらく違いに気付くことはないでしょうが)、さらに重要なことに、同じレベルの安全性を維持しながら、コードをよりクリーンで読みやすくします。

于 2010-05-27T16:50:54.987 に答える
5

昨年の Delphi Developer days で、私は Marco Cantu のコードのプライベートな隠し場所をいくつか見ました。彼は何かを作成するたびに try finally を呼び出します。

誰かが彼にそれについて尋ねたところ、彼はいつもそうしようとしていると言いました.

しかし、マルチスレッド コードでクリティカル セクションに出入りする場合は特に良い考えです。

明らかに、それは少し目立たない場合もあります。職場環境の文化に、頑強さを際立たせる文化がなければ、あなたは良い靴のように見えるかもしれません. しかし、それは良い考えだと思います。これは、強制的な手動ガベージ コレクションに対する Delphi の試みのようなものです。

于 2010-05-27T17:33:28.947 に答える
5

質問のパート 2 に答えるには、
try finallyほとんどオーバーヘッドがありません。

実際、暗黙の try...finally ブロックを持つメソッドはたくさんあります。たとえば、任意の Interface タイプのローカル var を使用する関数を持ち、その値を代入するだけです。

--jeroen

于 2010-05-27T17:07:53.830 に答える
2

クラスのコンストラクターでオブジェクトを作成していて、そのオブジェクトが外側のクラスによって所有される場合は、所有するクラスのデストラクターでオブジェクトを解放する必要があります。

Free を呼び出す代わりに、FreeAndNil() を使用する傾向があります。

編集:しかし、他の人が言ったように、あなたは間違いなくあなたが作成したものを解放したいと思っています.

于 2010-05-27T17:26:35.063 に答える
1

はい、オブジェクトを作成するコードがそれを解放する責任がある場合、それは常に良い考えです(必須)。そうでない場合、try/finally は適切ではありませんが、どちらも .Free ではありません。

ただし、このボイラープレート コードを「ビジネス ロジック」に追加するのは面倒な場合があり、オブジェクトを解放するのと同じ保証があるが、はるかにクリーンな (そして他の利点がある) アプローチを検討することをお勧めします。たとえば、私の独自の AutoFree() 実装

AutoFree() を使用すると、コードを次のように記述できます。

aObject := TObject.Create;
AutoFree(@aObject);

aObject.AProcedure();

あるいは、実装は参照への参照を使用するため (auto-NIL と Free を有効にするため)、そのようなハウスキーピング宣言を遠ざけるために AutoFree にしたい参照を事前登録することもできます。ビジネスロジックから解放し、コードの真の「肉」を可能な限りきれいに保ちます (これは、潜在的に複数のオブジェクトを解放する必要がある場合に特に有益です):

AutoFree(@aObject1);
AutoFree(@aObject2);

aObject1 := TObject.Create;
aObject1.AProcedure();

// Later on aObject2 is (or may be) also created
 :

私の最初の投稿には示されていませんが、単一の AutoFree() 呼び出しで複数の参照を登録することをサポートするメカニズムへの後で追加されたものですが、必要に応じて、これをサポートするために必要な変更を自分で把握できると確信しています。これを行うことができます:

AutoFree([@aObject1, @aObject2]);

aObject1 := TObject.Create;
aObject1.AProcedure();

// Later on aObject2 is (or may be) also created
 :
于 2010-05-27T21:26:45.480 に答える
-4

そうすることが強く推奨されていても、私はいつもそうするとは限りません。

try/finally を使用するかどうかの私のルール:

  • そのオブジェクトがクラッシュして燃える可能性。
  • オブジェクトが作成された回数。オブジェクトがめったに作成されないことがわかっている場合 (アプリケーションの有効期間で 5 ~ 6 回以内)、20KB のメモリ リークに耐えることができます。
  • オブジェクトがクラッシュした場合にリークするメモリの量。
  • コードの複雑さ。try/except は、コードを非常に見苦しくしています。5 行の手順がある場合は、常に try/except を使用します。
  • アプリケーション ファイルのスパン。アプリケーションを何日も実行する必要がある場合は、メモリの一部を解放したいと思います。そうしないと、リークが蓄積されます。

決定を下すのが難しい唯一の場所は、オブジェクトを何千回も作成するときにパフォーマンスが必要な場合です (ループなど)。この場合、オブジェクトが単純なタスクを実行していて、クラッシュする可能性がわずかにある場合は、try/except を使用しません。

于 2010-05-27T20:33:37.533 に答える