Delphi TList of records

后端 未结 8 996
遥遥无期
遥遥无期 2020-12-13 02:55

I need to store a temporary list of records and was thinking that a TList would be a good way to do this? However I am unsure how to do this with a TList<

相关标签:
8条回答
  • 2020-12-13 03:21

    The easiest way is to create your own descendant of TList. Here's a quick sample console app to demonstrate:

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils, Classes;
    
    type
      PMyRec=^TMyRec;
      TMyRec=record
        Value: Integer;
        AByte: Byte;
      end;
    
      TMyRecList=class(TList)
      private
        function Get(Index: Integer): PMyRec;
      public
        destructor Destroy; override;
        function Add(Value: PMyRec): Integer;
        property Items[Index: Integer]: PMyRec read Get; default;
      end;
    
    { TMyRecList }
    
    function TMyRecList.Add(Value: PMyRec): Integer;
    begin
      Result := inherited Add(Value);
    end;
    
    destructor TMyRecList.Destroy;
    var
      i: Integer;
    begin
      for i := 0 to Count - 1 do
        FreeMem(Items[i]);
      inherited;
    end;
    
    function TMyRecList.Get(Index: Integer): PMyRec;
    begin
      Result := PMyRec(inherited Get(Index));
    end;
    
    var
      MyRecList: TMyRecList;
      MyRec: PMyRec;
      tmp: Integer;
    begin
      MyRecList := TMyRecList.Create;
      for tmp := 0 to 9 do
      begin
        GetMem(MyRec, SizeOf(TMyRec));
        MyRec.Value := tmp;
        MyRec.AByte := Byte(tmp);
        MyRecList.Add(MyRec);
      end;
    
      for tmp := 0 to MyRecList.Count - 1 do
        Writeln('Value: ', MyRecList[tmp].Value, ' AByte: ', MyRecList[tmp].AByte);
      WriteLn('  Press Enter to free the list');
      ReadLn;
      MyRecList.Free;
    end.
    

    This eliminates a couple of things:

    • It handles freeing the memory.
    • You don't have to typecast everything to use it.

    As Remy and Warren both said, it's a little more work because you have to allocate the memory when you add new records.

    0 讨论(0)
  • 2020-12-13 03:21

    If using an older version of Delphi where generics isn't present, consider inheriting from TList and override Notify method. When adding an item, alloc memory, copy added pointer memory content and override content in list. When removing, just free memory.

      TOwnedList = class(TList)
      private
        FPtrSize: integer;
      protected
        procedure Notify(Ptr: Pointer; Action: TListNotification); override;
      public
        constructor Create(const APtrSize: integer);
      end;
    
      constructor TOwnedList.Create(const APtrSize: integer);
      begin
        inherited Create();
        FPtrSize := APtrSize;
      end;
    
      procedure TOwnedList.Notify(Ptr: Pointer; Action: TListNotification);
      var
        LPtr: Pointer;
      begin
        inherited;
        if (Action = lnAdded) then begin
          GetMem(LPtr, FPtrSize);
          CopyMemory(LPtr, Ptr, FPtrSize); //May use another copy kind
          List^[IndexOf(Ptr)] := LPtr;
        end else if (Action = lnDeleted) then begin
          FreeMem(Ptr, FPtrSize);
        end;
      end;
    

    Usage:

    ...
    LList := TOwnedList.Create(SizeOf(*YOUR RECORD TYPE HERE*));
    LList.Add(*YOU RECORD POINTER HERE*);
    ...
    
    • Note that where I did use CopyMemory(LPtr, Ptr, FPtrSize), you may use another copy aproach. My list is intended to store a record with pointer references, so it doesn't manage it's fields memory.
    0 讨论(0)
提交回复
热议问题