Yes,
Like marcov has pointed out, Initialize/Finalize won't work on a VAR pointer, it has no TypeInfo for it too work from.
But if your willing to pass the TypeInfo to the procedure, then you can make a function to clear the record.
It's not complete for all field types, but if you look at the source you should be able to figure out what to change. For simple types just add them to the SimpleClear Enum, and for managed types update the case statement, I've done AnsiString & Widestring to get you started.
Once done, clearing a record is as simple as ->
ClearRecord(Rec,typeinfo(Rec));
The only problem I foresee, is if the RTTI structure for Records change in the future, so be aware of this.
Here is an example ->
program project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
// Classes,
SysUtils, typinfo
{ you can add units after this };
type
PTest = ^TTest;
TTest = record
str1:string;
str2:widestring;
int1:integer;
end;
procedure ShowRec(const r:TTest);
begin
writeln('str1 = '+r.str1);
writeln('int1 = '+inttostr(r.int1));
writeln('widestr = '+r.str2);
end;
type
PRecordElement=^TRecordElement;
TRecordElement=packed record
TypeInfo: Pointer;
Offset: Longint;
end;
PRecordInfo=^TRecordInfo;
TRecordInfo=packed record
Size: Longint;
Count: Longint;
{ Elements: array[count] of TRecordElement }
end;
const
SimpleClear = [ tkInteger, tkInt64, tkUChar, tkQWord ];
procedure ClearRecord(var x; tp:PTypeInfo);
var
p,pt,pdata:PByte;
eti:PTypeInfo;
pr:PRecordInfo;
re:PRecordElement;
l,lastoffset:integer;
SimpleClearLast:boolean;
begin
p := @x;
if PTypeInfo(tp)^.Kind <> tkRecord then
raise Exception.Create('Var not a record');
pr := PRecordInfo(
PByte(tp)+ord(PTypeInfo(tp)^.Name[0]) +1 +sizeof(TTypeKind));
re := PRecordElement(
PByte(pr)+sizeof(TRecordInfo));
lastoffset := 0;
SimpleClearLast := false;
for l := 0 to pr^.Count-1 do
begin
if SimpleClearLast then
FillByte( (p+lastoffset)^, re^.Offset - lastoffset, 0);
eti := PTypeInfo(re^.TypeInfo);
if eti^.Kind in SimpleClear then
SimpleClearLast := true
else begin
SimpleClearLast := false;
pdata := pbyte(p+re^.offset);
case PTypeInfo(re^.TypeInfo)^.Kind of
tkAString: PAnsiString(pdata)^ := '';
tkWString: PWideString(pdata)^ := '';
else
raise Exception.Create('type not implemented:'+
GetEnumName(TypeInfo(TTypeKind),ord(PTypeInfo(re^.TypeInfo)^.Kind)));
end;
end;
lastoffset := re^.Offset;
inc(re,1);
end;
if SimpleClearLast then
FillByte( (p+lastoffset)^, pr^.Size - lastoffset,0);
end;
procedure DoTest;
var
pRec:PTest;
Rec:TTest;
begin
Rec.str1:='These should';
Rec.str2:='Clear';
Rec.int1:=99;
ShowRec(Rec);
writeln('Now clear...');
ClearRecord(Rec,typeinfo(Rec));
ShowRec(Rec);
end;
begin
DoTest;
end.
The output on my machine ->
str1 = These should
int1 = 99
widestr = Clear
Now clear...
str1 =
int1 = 0
widestr =
Heap dump by heaptrc unit
71 memory blocks allocated : 1641/1792
71 memory blocks freed : 1641/1792
0 unfreed memory blocks : 0
True heap size : 163840 (96 used in System startup)
True free heap : 163744