用于增加指针数组的通用函数

时间:2012-08-03 12:00:27

标签: arrays delphi pointers

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

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:我没有太多的指针背景和那种编程,我当然会使用对象和动态链表,但在这种情况下它是遗留代码而我无法改变它,至少对于现在

1 个答案:

答案 0 :(得分:2)

<强>更新

这不是一个完整的答案。使用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.