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