arrays – 增加指针数组的通用函数

我正在使用具有如下数据结构的代码:

type
  TData1 = record
    IntField: Integer;
    StrField: string;
  end;

  TData2 = record
    DateField: TDateTime;
    StrField: string;
  end;

var
  AData1 = array of ^TData1;
  AData2 = array of ^TData2;

有时我必须向其中一个数组添加一个元素,如下所示:

L := Length(AData1);
SetLength(AData1, L + 1);
New(AData1[L]);

我如何编写一个程序来完成增加数组大小和为任何类型的指针工作的新项目分配内存的工作?并且必须在不更改记录(TData1,TData2)和数组(AData1,AData2)的定义的情况下完成,因此它不会破坏现有代码.

Ps:我没有太多的指针背景和那种编程,我当然会使用对象和动态链表,但在这种情况下它是遗留代码,我不能改变它,至少现在.

最佳答案 更新:

这不是一个完整的答案.使用David提到的TDynArray可以解决您的问题.

使用RTTI我为您提供了另一种解决方案.它是一种通用解决方案,您可以轻松添加更多功能/功能.它将保留您的类型声明.包括添加/删除记录的示例.

记录TDynPtArray处理指向记录的任何动态指针.它使用Init调用初始化:

DPA.Init(TypeInfo(TData1), AData1);
Data1 := DPA.Add;  // Adds a record with default values and
                   // returns a pointer to the record
DPA.Remove; // Finalizes/deallocates the last record and 
            // shrinks the dynamic array

uses
  Windows,System.SysUtils,System.TypInfo;

Type
  TPtArray = array of Pointer;
  PPtArray = ^TPtArray;
  TDynPtArray = record
  private
    FDynArray: PPtArray;
    FTypeInfo: PTypeInfo;
    FTypeData: PTypeData;
  public
    constructor Init( T: Pointer; var dynArray);
    function Add : Pointer;
    procedure Remove;
    procedure Clear;
  end;

constructor TDynPtArray.Init(T: Pointer; var dynArray);
begin
  FTypeInfo := T;
  if  (FTypeInfo^.Kind <> tkRecord) then
    raise Exception.CreateFmt('%s is not a record',[FTypeInfo^.Name]);
  FTypeData := GetTypeData( FTypeInfo);
  FDynArray := @dynArray;
end;

function TDynPtArray.Add: Pointer;
var
  L: integer;
begin
  L := Length(FDynArray^);
  SetLength(FDynArray^,L+1);
  GetMem( FDynArray^[L], FTypeData^.elSize);
  ZeroMemory( FDynArray^[L], FTypeData^.elSize);
  Result := FDynArray^[L];
end;

procedure RecordClear(var Dest; TypeInfo: pointer);
asm
{$ifdef CPUX64}
  .NOFRAME
{$endif}
  jmp System.@FinalizeRecord
end;

procedure TDynPtArray.Remove;
var
 L: integer;
begin
  L := Length(FDynArray^);
  if (L = 0) then
    exit;
  RecordClear( FDynArray^[L-1]^,FTypeInfo); // Finalize record
  FreeMem( FDynArray^[L-1], FTypeData^.elSize);
  SetLength(FDynArray^,L-1);
end;

procedure TDynPtArray.Clear;
begin
  while (Length(FDynArray^) <> 0) do
    Self.Remove;
end;

还有一点测试:

type
  PData1 = ^TData1;
  TData1 = record
    IntField: Integer;
    StrField: string;
  end;
  TData1Arr = array of PData1;

var
  AData1: TData1Arr;
  Data1: PData1;
  DPA: TDynPtArray;
begin
  DPA.Init(TypeInfo(TData1), AData1);
  Data1:= DPA.Add;
  Data1^.StrField := '111';
  WriteLn(Data1^.IntField);
  WriteLn(Data1^.StrField);

  DPA.Clear;

  ReadLn;
end.
点赞