8

私のコードでは、さまざまな場所で作成された小さなデータ保存クラスを使用しています。メモリリークを回避し、物事を単純化するために、参照カウントを使用したいので、

type TFileInfo = class (TInterfacedObject, IInterface)

TFileInfo.Freeへの手動呼び出しをすべて削除しました。残念ながら、Delphiは多くのメモリリークを報告しました。SOで検索すると、これが機能しない理由を説明する次の質問が見つかりました。

TInterfacedObjectガベージの子孫が収集されないのはなぜですか?

そこに回避策が示されていますが、(少なくとも正しく理解できれば)カスタムインターフェイスIFileInfoを作成し、多くのゲッターとセッターを提供する必要があります。これは避けたいものです。

編集私は、create FileInfoオブジェクトを2つの異なる種類のハッシュテーブルに挿入することを追加する必要があります。1つはTBucketListから派生し、もう1つはCodegearフォーラムのハッシュマップ実装です。内部的には両方ともユーザーポインタであるため、状況は他の質問と同じです。

Delphiのオブジェクトに参照カウントを使用させる他の可能性はありますか?

4

7 に答える 7

8

Delphiでの参照カウントは、インターフェイスを介したインスタンスへの参照しかない場合にのみ機能します。インターフェイス参照とクラス参照を混在させるとすぐに問題が発生します。

基本的に、すべてのメソッドとプロパティが定義されたインターフェイスを作成する必要なしに、参照カウントが必要です。これを行うには3つの方法があり、これらはおおよそ私が推奨する順序です。

  1. バリーケリーはスマートポインタについての投稿を書きました。Delphi 2009のジェネリックスを使用していますが、2009をまだ使用していない場合は、使用しているタイプの特定のバージョンにハードコーディングできると確信しています(これは素晴らしいリリースです)。

  2. より多くのバージョンのDelphiでより少ない変更で機能する別の方法は、JanezAtmapuriMakovsekによる値型ラッパーです。これはTStringListに実装された例ですが、任意のタイプに適合させることができます。

  3. 3番目の方法は、インターフェイスポインターを作成することです(Barryのスマートポインターに似ていますが、それほどスマートではありません)。JCLに1つあると思いますが、詳細はよく覚えていません。基本的に、これは構築時にTObject参照を受け入れるインターフェースです。次に、参照カウントがゼロに達すると、渡されたオブジェクトを解放します。このメソッドは、実際に使用される参照から参照カウント参照を分離するため、パラメーターとして渡さない短期間のインスタンスに対してのみ実際に機能します。代わりに、他の2つの方法のいずれかをお勧めしますが、この方法を希望し、詳細が必要な場合は、お知らせください。

それがDelphiのことです。物事を成し遂げるには、自由な方法があります。オプション#1は私の意見では最高です-Delphi 2009を入手し、可能であればその方法を使用してください。

幸運を!

于 2009-04-23T17:03:51.013 に答える
6

残念ながら、Delphiコンパイラは、インターフェイス(この場合はカスタムインターフェイスIFileInfo)を使用する場合にのみ、参照カウントをinc/decするために必要なコードを生成します。さらに、インターフェースがポインター(またはそのことについてはTObject)にキャストされている場合も、参照カウントはできません。たとえば、グローバル変数リストを想定すると:TList:

var ifi : IFileInfo;
begin
  ifi := TFileInfo.Create;
  list.Add(TFileInfo(ifi));
end;

メソッドがlist[list.Count--1]を返した後、ダングリングポインタが含まれます。

したがって、インターフェイスをポインタにキャストするハッシュマップで使用することはできません。ハッシュマップの実装では、インターフェイスをIInterfaceとして保持する必要があります。

于 2009-04-23T10:42:10.977 に答える
4

オブジェクト参照とインターフェース参照を混在させないでください。

var
  Intf: IInterface;
  Obj: TFileInfo;

begin
  // Interface Reference
  Intf := TFileInfo.Create; // Intf is freed by reference counting, 
                            // because it's an interface reference
  // Object Reference
  Obj := TFileInfo.Create;
  Obj.Free; // Free is necessary

  // Dangerous: Mixing
  Obj := TFileInfo.Create;
  Intf := Obj; // Intf takes over ownership and destroys Obj when nil!
  Intf := nil; // reference is destroyed here, and Obj now points to garbage
  Obj.Free; // this will crash (AV) as Obj is not nil, but the underlying object
            // is already destroyed
end;
于 2009-04-23T14:37:16.277 に答える
3

この機能はインターフェースには提供されますが、オブジェクトには提供されません。

そのようなものを作成することはできますが、TObjectの構造の一部をオーバーライドする必要があります。

TRefCountObject = class (TObject)
private
  FRefCount : Integer;
public
  constructor Create;

  procedure Free; reintroduce;

  function RefCountedCopy: TRefCountObject;
end;


constructor TRefCountObject.Create;
begin
  inherited;
  FRefCount := 1;
end;

procedure TRefCountObject.Free;
begin
  if self=nil then Exit;
  Dec(FRefCount);
  if FRefCount<=0 then
    Destroy;
end;

function TRefCountObject.RefCountedCopy: TRefCountObject;
begin
  Inc(FRefCount);
  Result := self;
end;

オブジェクトを別の変数に割り当てるには、RefCountedCopyが必要です。しかし、その後、refcountedオブジェクトがあります。

これを使用する方法:

var1 := TRefCountObject.Create;   // rc = 1
var2 := var1.RefCountedCopy;      // rc = 2
var3 := var1.RefCountedCopy;      // rc = 3
var2.Free;                        // rc = 2
var1.Free;                        // rc = 1
var4 := var3.RefCountedCopy;      // rc = 2
var3.Free;                        // rc = 1
var4.Free;                        // rc = 0
于 2009-04-23T10:36:13.907 に答える
3

TObjectインスタンスでのfreeの呼び出しを排除したい場合は、ネイティブDelphiのガベージコレクターを確認することをお勧めします。私は2つの異なるガベージコレクターとガベージコレクション手法を知っています。それぞれに長所と短所があります。

それらの1つはおそらくあなたのために働くでしょう。

于 2009-04-23T18:38:34.610 に答える
1

すでに述べたことに加えて、インターフェイスへの参照を保存する場合は、TListを使用する代わりに、TInterfaceListを使用します。refカウントは一貫して機能します。

于 2009-04-23T17:14:17.010 に答える
0

これには長い説明がありますが、簡単に言うと、TInterfacedObjectから継承する(そして自分でFreeを呼び出さない)だけでは不十分です。object-factory-dynamicを使用してオブジェクトを作成し、interface-pointersを使用してobject-reference-variablesだけでなく、あらゆる場所のオブジェクト。(はい、それはあなたがそれを見ずに「古いコード」を単に切り替えることができないことを意味します)

于 2009-04-23T11:04:36.413 に答える