4

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

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

4

1 回答 1

2

更新:

这不是一个完整的答案。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.
于 2012-08-03T18:51:12.287 回答