web-dev-qa-db-ja.com

ランタイムフォームを動的に作成/リリースする正しい方法は何ですか?

私は常にメモリ使用量を念頭に置いてアプリケーションを作成しようとしています。必要がない場合は作成しないでください。これが私の見方です。

とにかく、例として以下を取り上げます。

Form2:= TForm2.Create(nil);
try
  Form2.ShowModal;
finally
  Form2.FreeOnRelease;
end;

私は実際にForm2.Destroyがおそらくより良いオプションだと思います。それは私の質問に私をもたらします。

呼び出しの違いは何ですか:

Form2.Destroy;
Form2.Free;
Form2.FreeOnRelease;

私が何かを逃していない限り、それらはすべて同じまたは同様の仕事をします。

また、上記のいずれかをいつ使用する必要がありますか?オブジェクトを解放するときは明らかにそれを理解していますが、状況によっては、たとえばDestroyよりもFreeの方が適していますか?

17
user741875

Form2:= TForm2.Create(nil);

Form2はおそらく、IDEで作成されたTForm2を通常保持する、IDEで生成されたグローバル変数であるため、これはコードの臭いです。ほとんどの場合、ローカル変数と、より適切な名前の変数を使用することをお勧めします。これは必ずしもエラーではなく、コードの臭いです。

Form2.DestroyとForm2.Free

とにかくDestroyを呼び出すので、Form2.Freeを使用します。あなたはできる CTRL+Click 名前(Free)で、その実装を確認します。基本的に、Freeがnilでない場合、DestroySelfを呼び出します。

Form2.FreeOnRelease

ドキュメント が言うように、"It should not be necessary to call FreeOnRelease directly."

15
Cosmin Prund

FreeOnReleaseについてはこれまで聞いたことがありません。グーグルですばやく検索すると、その理由がわかりました。 公式ドキュメントから:

FreeOnReleaseは、コンポーネントによって実装されたインターフェースが解放されたときに呼び出されます。 FreeOnReleaseは内部で使用され、対応するインターフェイスメソッドを呼び出します。 FreeOnReleaseを直接呼び出す必要はありません。

FreeDestroyについては、Freeが安全機能です。基本的にはif self <> nil then self.Destroy;として実装され、コンストラクタとデストラクタを安全に使用できるようにするために作成されました。基本的な考え方は次のとおりです。

オブジェクトを作成していて、未処理の例外が発生した場合、デストラクタが呼び出されます。オブジェクトに他のオブジェクトが含まれている場合、エラーが発生するまでにオブジェクトがまだ作成されている場合とされていない場合があるため、すべてのオブジェクトでDestroyを呼び出そうとすることはできません。ただし、作成されたものが確実に破棄されるようにする方法が必要です。

Delphiはコンストラクタを呼び出す前にオブジェクトのアドレス空間をゼロにするため、まだ作成されていないものはすべて、この時点でnilであることが保証されます。したがって、すべてのサブオブジェクトに対して何度もif FSubObject <> nil then FSubObject.Destroyと言うことができます(アクセス違反が発生することを忘れた場合)。または、Freeメソッドを使用できます。あなたのためにそれ。 (これは、コンストラクターが呼び出される前にメモリスペースが not ゼロになるC++に比べて大幅に改善されています。これには、すべてのサブオブジェクトをスマートポインターでラップし、RAIIを使用して例外安全性を維持してください!)

他の場所でも便利で、使わない理由はありません。 Freeが測定可能なパフォーマンスの低下をもたらし、コードの安全性が向上することに気づいたことはありません。したがって、すべての場合に使用することをお勧めします。

そうは言っても、フォームを具体的に扱う場合、方程式に組み込む追加の変数があります。それはWindowsメッセージキューです。解放しようとしているフォームの保留中のメッセージがまだあるかどうかわからないため、フォームでFreeを呼び出すことが常に安全であるとは限りません。そのために、Releaseメソッドがあります。キューにメッセージを投稿して、処理するメッセージがなくなるとフォームが自動的に解放されるようにするため、通常は、不要になったフォームを解放するための最良の方法です。

10
Mason Wheeler

正規の形式は次のとおりです。

Form := TMyForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;

Destroyを呼び出さないでください。代わりに、常にFreeを呼び出してください。

FreeOnReleaseは完全に赤いニシンです。フォームまたはその子宛てのキューに入れられたメッセージがある場合は、Releaseを呼び出すことを選択する場合がありますが、多くの場合、これは設計上の問題を示しています。

6
David Heffernan

慣用的な用法は

_procedure SomeProc;
var
  frm: TForm2;
begin
  frm := TForm2.Create(nil);
  try
    frm.ShowModal;
  finally
    frm.Free;
  end;
end;
_

または、with構文が嫌いでない限り、

_with TForm2.Create(nil) do
  try
    ShowModal;
  finally
    Free;
  end;
_

ドキュメント によると、決してDestroyを呼び出さないでください。実際、Freeは_if Self <> nil then Destroy;_とまったく同じです。つまり、これはDestroyの「安全な」バージョンです。ポインタがたまたまnilの場合、完全にクラッシュすることはありません。 [これをテストするには、フォームクラスにプライベートフィールド_FBitmap: TBitmap_を追加してから、(たとえば)OnCreateで_FBitmap.Free_と_FBitmap.Destroy_を試してください。]

上記のアプローチを使用してフォームを作成する場合、フォームクラスで奇妙なことをしない限り、Freeは完全に安全です。

ただし、CreateForm(TForm2, Form2)を使用してフォームを作成し、フォームオブジェクトをグローバルインスタンス変数_Form2_に格納し、すぐに解放しない場合[たとえば、ウィンドウを固定したい場合メインフォームの横で非モーダルな方法で数分間]、おそらくReleaseの代わりにFreeを使用する必要があります。から ドキュメント

リリースは、フォームのすべてのイベントハンドラーとフォーム上のコンポーネントのイベントハンドラーの実行が終了するまでフォームを破棄しません。リリースは、フォームがリリースされる前に、フォームのイベントキュー内のすべてのメッセージが処理されることも保証します。フォームまたはその子のイベントハンドラーは、Free(Delphi)またはdelete(C++)の代わりにReleaseを使用する必要があります。そうしないと、メモリアクセスエラーが発生する可能性があります。

FreeOnRelease フォームとは特に関係ありません。ドキュメントから:

FreeOnReleaseを直接呼び出す必要はありません。

4

もう1つの方法は、caFreeをformoncloseのアクションに渡すことです。

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end
0
dawood karimy