5

私はDelphiにかなり慣れておらず、すべてのメモリ管理を手動で行っていますが、インターフェイスを使用して参照カウントを実行し、その方法でメモリ管理を提供できるDelphiへの参照を聞いたことがあります。それを始めたいのですが、いくつか質問があります。

  1. 一般的に、どのように使用しますか。インターフェイスとそれを実装するクラスを作成します。次に、そのオブジェクトが必要なときはいつでも、変数は実際にはインターフェイスタイプですが、オブジェクトをインスタンス化してプレストしますか?それを解放することを考える必要はありませんか?これ以上試してはいけません-最終的に?

  2. 本当にそれらを必要としないクラスのためにたくさんのインターフェースを作成することは非常に面倒に思えます。それらを自動生成するためのヒントはありますか?どうすればそれを整理するのが最善ですか?同じファイル内のインターフェイスとクラス?

  3. 私に悲しみを引き起こす可能性のある一般的な落とし穴は何ですか?例:インターフェイスオブジェクトをそのクラスのオブジェクトにキャストすると、参照カウントが壊れますか?または、Delphiが参照ループを作成する非自明な方法はありますか?(AがBを使用する以外にCがAを使用することを意味します)

これのいずれかをカバーするチュートリアルがあれば、それは素晴らしいことですが、私は検索で何も思いつきませんでした。ありがとう。

4

5 に答える 5

8

私は現在、メモリ管理の目的でインターフェイス参照カウントの「副作用」を利用する非常に大規模なプロジェクトに取り組んでいます。

私自身の個人的な結論は、「無料で電話することを心配する必要はない」という理由以外に、非常に複雑なコードがたくさんあるということです。

いくつかの非常に基本的な理由から、この一連の行動に反対することを強くお勧めします。

1)COM互換性の目的で存在する副作用を使用しています。

2)オブジェクトのフットプリントと効率をより重くします。インターフェイスは、ポインタのリストへのポインタです。またはそれらの線に沿ったものです。

3)あなたが述べたように...あなたは今、自分でメモリを解放することを避けるという唯一の目的のためにインターフェースの山を作らなければなりません...これは私の意見の価値よりも多くの問題を引き起こします。

4)デバッグするのに非常に苦労する最も一般的なバグは、オブジェクトが参照される前に解放されたときに発生します。ソフトウェアが公開される前にこの問題をテストするために、独自の参照カウントに特別なコードがあります。

今あなたの質問に答えるために。

1)TFooとインターフェースIFooが与えられた場合、次のようなメソッドを持つことができます

function GetFoo: IFoo;
begin
  Result := (TFoo.Create as IFoo);
end;

...そしてプレスト、あなたはそれを解放するために最終的に必要はありません。

2)はい、私が言ったように、それは素晴らしいアイデアだと思いますが、それはブプキの大きな痛みになります

3)2つの問題。

A)Object1.Interface2とObject2.Interface1があります...これらのオブジェクトは循環参照のために解放されることはありません

B)すべての参照が解放される前にオブジェクトを解放すると、これらのバグを追跡するのがどれほど難しいかを強調することはできません...

于 2012-08-02T20:28:05.683 に答える
8

Delphiでの「自動ガベージコレクション」の要望につながる最も一般的な苦情は、短命の一時的なオブジェクトでさえ手動で破棄する必要があり、確実にするためにかなりの量の「ボイラープレート」コードを作成する必要があるという方法です。これは、例外が発生したときに発生します。

たとえば、プロシージャ内で一時的な並べ替えやその他のアルゴリズムの目的でTStringListを作成します。

procedure SomeStringsOperation(const aStrings: TStrings);
var
  list: TStringList;
begin
  list := TStringList.Create;
  try
      :
     // do some work with "list"
      :
  finally
    list.Free;
  end;
end;

あなたが述べたように、参照カウント寿命管理のCOMプロトコルを実装するオブジェクトは、それらへのすべての参照が解放されたときに自分自身をクリーンアップすることによってこれを回避します。

ただし、TStringListはCOMオブジェクトではないため、これが提供する便利さを享受することはできません。

幸い、COM参照カウントを使用して、使用するクラスのすべての新しいCOMバージョンを作成しなくても、これらの処理を行う方法があります。完全にCOMベースのモデルに切り替える必要はありません。

非常に単純なユーティリティクラスを作成して、この自動クリーンアップ動作を実現するために、軽量のCOMコンテナ内に任意のオブジェクトを「ラップ」できるようにしました。この手法を使用すると、上記の例を次のように置き換えることができます。

procedure SomeStringsOperation(const aStrings: TStrings);
var
  list: TStringList;
begin
  AutoFree(@list);

  list := TStringList.Create;

    :
  // do some work with "list"
    :
end;

AutoFree ()関数呼び出しは、プロシージャ用にコンパイラによって生成された終了コードでRelease() 'dである「匿名」インターフェイスオブジェクトを作成します。この自動解放オブジェクトには、解放したいオブジェクトを参照する変数へのポインターが渡されます。特に、これにより、AutoFree()関数を疑似「宣言」として使用できるようになり、すべてのAutoFree()呼び出しを、メソッドの先頭で、参照する変数宣言のできるだけ近くに配置できます。オブジェクトも作成しました。

ソースコードやその他の例を含む実装の完全な詳細は、この投稿の私のブログにあります。

于 2012-08-02T20:53:52.947 に答える
3

インターフェイスのメモリ管理は、TInterfacedObjectによって実装される_AddRefおよび_Releaseの実装を通じて行わます

一般に、インターフェイスを使用してメモリ管理の煩わしさを軽減することは良い考えですが、次のことに注意する必要があります。

  • インターフェイスを実装するクラスが、およびにTInterfacedObject適切な実装を提供する独自の祖先クラスから派生するか、ロールすることを確認してください。_AddRef_Release
  • いずれか/または:を使用してください。したがって、ユーザーインターフェイス参照またはオブジェクトインスタンス参照を使用する場合は、それらを混在させないでください。これは、コンポーネントにインターフェイスを実装するときに問題になる可能性があります(コンポーネントはから派生するため、TComponentではなくTInterfacedObject
  • 所有者ベースのメモリ管理と/ベースのメモリ管理が混在しているため、 TInterfacedComponentの方法を使用しないでください_AddRef_Release
  • 循環インターフェイス参照を監視します(ここで説明され、ここで実装されている「弱いインターフェイス参照」の実装を回避できます
  • 公開するクラスのパーツのインターフェイスを定義する必要があるため、追加のコードを維持し、それら2つを同期させる必要があります(このためにModel Makerコードエクスプローラーを使用できます。これにより、インターフェイスを抽出し、一般にシングルアクションでコードのインターフェース/実装部分を管理するため、開発)
  • 基礎となるクラスのインスタンスを作成するには、追加の配管が必要です。そのためにファクトリパターンを使用できます。

これは必ずしも効果的ではありませんが、根本的な質問のいくつかに答えます。

于 2012-08-03T06:51:17.150 に答える
0

考えられる最短の答え:デフォルトのデルファイメモリモデルは、所有者が所有するオブジェクトを解放することです。他のすべての参照は弱参照であり、所有者が手放す前に手放す必要があります。アプリの全有効期間よりも有効期間が短いオブジェクトを「共有」することはめったに行われません。参照カウントが行われることはめったにありません。行われる場合は、専門家によってのみ行われるか、解決するよりも多くのバグやクラッシュが追加されます。

慣用的なデルフィスタイルを学び、それを模倣してみてください。穀物と戦わないでください。悲しいことに、人々は「実装ではなく、インターフェースに対するプログラム」は「どこでもIUnknownを使用する」ことを意味すると考えています。それは真実ではない。COM IUnknownインターフェイスを使用せず、代わりに抽象基本クラスを使用することをお勧めします。できない唯一のことは、1つのクラスに2つの抽象基本クラスを実装することであり、その必要性はまれです。

更新:最近、COMインターフェイス(IUnknownベース)を使用して、モデルとコントローラーの実装をUIクラスから分離するのに役立つことがわかりました。したがって、IUnknownベースのインターフェイスを使用すると便利です。しかし、あなたの努力の基礎となるドキュメントや先行技術はそれほど多くありません。インターフェースと非インターフェースベースのライフタイム管理を組み合わせるという通常の問題や、慣れている間に発生するすべての問題なしに、人々がこれらすべてをレイアウトできる「クックブック」スタイルのレシピを見たいと思います。その余分な複雑さ。

于 2012-08-06T00:19:05.140 に答える
0

手動のFreeを回避するためだけにインターフェースに切り替えるのは無意味です。Free / try-finally行の経済性はほとんどなく、intf / class宣言の同期を維持する必要性に言及せずに、インターフェイスでg/setterとプロパティの両方を宣言する必要性をほとんど補うことはできません。インターフェイスは、暗黙的なファイナライズコードと参照カウントによるパフォーマンスの低下ももたらします。パフォーマンスが重要ではなく、自動解放だけを実現したい場合は、Delticsが提案したようなユニバーサルインターフェイスラッパーを使用することをお勧めします。

于 2015-01-12T08:32:24.187 に答える