0

Delphi の TList クラスに似たシーケンシャル リンク リスト クラスを実装しようとしていました。ここでは、ユーザーが count プロパティを設定できるようにする代わりに、クラスは count プロパティを自動的にインクリメント/デクリメントします。そのため、setcount プロシージャ内で配列を初期化する代わりに、クラスはオブジェクト参照を配列に追加する直前に配列要素を初期化します。コードは次のとおりです。

    PObjectarray = ^TObjectarray;
    TObjectarray = array of TObject;
    TSequentialList = class
    private
      FObjects: PObjectarray;
      FCapacity: Integer;
      FCount: Integer;
    protected
      procedure GrowList;virtual;
      procedure SetCapacity(aValue: Integer);
    public
      constructor Create(aCapacity: Integer); overload;
      Constructor Create;overload;
      procedure Add(aObject:TObject);
      procedure Delete(aIndex:Integer);
      destructor Destroy;override;    
   End;

実装: -

    procedure TSequentialList.Add(aObject: TObject);
    begin
      if FCount=FCapacity then
        GrowList;
      FillChar(FObjects^[FCount],sizeof(TObject),0);//Initialize the FCount's member space
      FObjects^[FCount]:=aObject;
      Inc(FCount);
    end;

    constructor TSequentialList.Create(aCapacity: Integer);
    begin
      FCapacity := 0;
      FCount := 0;
      SetCapacity(aCapacity);
    end;

    constructor TSequentialList.Create;
    begin
      FCapacity := 0;
      FCount := 0;
    end;

    procedure TSequentialList.Delete(aIndex: Integer);
    var tmpObj:TObject;
    i:Integer;
    begin
     if (aIndex>=FCount) or (aIndex<0) then raise ELinkedListException.Create('Invalid Index in Delete..!');
     tmpObj:=FObjects^[aIndex];
     tmpObj.Free;

     System.Move(FObjects^[aIndex+1],FObjects^[aIndex],(FCount-aIndex)* SizeOf(TObject));
     Dec(FCount);
    end;

    destructor TSequentialList.Destroy;
    begin
      SetCapacity(0);
      inherited;
    end;

    procedure TSequentialList.GrowList;
    var delta:Integer;
    begin
      if FCapacity>64 then
        delta:=FCapacity div 64
      else if FCapacity>16  then
           delta:=8
      else delta:=4;
      SetCapacity(FCapacity+delta);
    end;

    procedure TSequentialList.SetCapacity(aValue: Integer);
    var i:Integer;
    begin
      if FCapacity <> aValue then begin
         if aValue<FCount then begin
            for i := FCount-1 downto  aValue do
               Delete(i);
         end;
         ReallocMem(FObjects, aValue*sizeof(TObject));
         FCapacity := aValue;
      end;
    end;

使用法: //機能しません

    procedure TForm2.Button1Click(Sender: TObject);
    var lst:TSequentialList;
    obj:TIntObj;
    begin
      lst:=TSequentialList.Create(4);
      obj:=TIntObj.Create(10);
      lst.Add(obj);
      lst.Add(TIntObj.Create(20));
      lst.Free;
    end;

上記の方法を終了すると、システムがハングします。プログラムの何が問題なのか教えてください。

4

2 に答える 2

1

まず第一に、これはリンクされたリストではありません。それは非常に異なる構造です。さらに、 を再実装するのではなく、TObjectListDelphi で提供されている組み込みクラスをそのまま使用する必要があります。


コードの根本的な問題は、動的配列を正しく使用していないことです。のような生の割り当て関数を使用してはなりませんReallocMem。などの関数はGetMemReallocMem生のポインターで使用するためのものです。動的配列の有効期間は、コンパイラ/ランタイム ライブラリによって管理されます。

動的配列を割り当てるには、 を使用する必要がありますSetLength

もう 1 つの重大なエラーは、 への呼び出しがSystem.Move間違った数の要素を移動することです。

以下のコードは、コードを簡略化して修正したものです。

type
  TMyObjectList = class
  private
    FObjects: array of TObject;
    FCount: Integer;
  protected
    procedure GrowList;
    procedure SetCapacity(aValue: Integer);
  public
    constructor Create(aCapacity: Integer); overload;
    constructor Create; overload;
    destructor Destroy; override;
    procedure Add(aObject: TObject);
    procedure Delete(aIndex: Integer);
  end;

constructor TMyObjectList.Create(aCapacity: Integer);
begin
  inherited Create;
  SetCapacity(aCapacity);
end;

constructor TMyObjectList.Create;
begin
  Create(0);
end;

destructor TMyObjectList.Destroy;
begin
  SetCapacity(0);
  inherited;
end;

procedure TMyObjectList.Add(aObject: TObject);
begin
  if FCount = Length(FObjects) then
    GrowList;
  FObjects[FCount] := aObject;
  Inc(FCount);
end;

procedure TMyObjectList.Delete(aIndex: Integer);
begin
  if (aIndex >= FCount) or (aIndex < 0) then
    raise Exception.Create('Invalid Index in Delete..!');

  FObjects[aIndex].Free;
  System.Move(FObjects[aIndex+1], FObjects[aIndex], 
    (FCount-aIndex-1)*SizeOf(TObject));
  Dec(FCount);
end;

procedure TMyObjectList.GrowList;
var
  delta: Integer;
begin
  if Length(FObjects) > 64 then
    delta := Length(FObjects) div 64
  else if Length(FObjects) > 16 then
    delta := 8
  else
    delta := 4;
  SetCapacity(Length(FObjects) + delta);
end;

procedure TMyObjectList.SetCapacity(aValue: Integer);
var
  i: Integer;
begin
  if Length(FObjects) <> aValue then
  begin
    for i := aValue to FCount-1 do
      FObjects[i].Free;
    SetLength(FObjects, aValue);
  end;
end;

ただし、機能することがわかっている組み込みの RTL クラスを使用することをお勧めします。たとえば、Delphi の最新バージョンを使用している場合は、.NET の汎用コンテナの 1 つを使用できますSystem.Generics.Collections。あなたの場合、TObjectList<T>必要なもののようです。古いバージョンの Delphi では、ユニットTObjectListから使用していました。Contnrs

于 2012-12-24T10:31:25.213 に答える
0

delete-methodのこの行は明らかに間違っています:

 for i := FCount-1 downto  aValue do
           Delete(i);

Delete(aValue)代わりに電話してください。

それにもかかわらず、あなたのコードはリンクリストを実装していません。TObjectListを実装しようとしているように見えます。

于 2012-12-24T07:46:47.667 に答える