是否有办法在运行时创建一个指向记录的类型指针?
E.g。在运行时实现与
中的pMyRecord赋值相同TMyRecord = record
s1: string;
s2: string;
end;
TpMyRecord = ^TMyRecord;
...
var pMyRecord: TpMyRecord;
begin
New(pMyRecord)
但没有TpMyRecord = ^TMyRecord
声明。
我知道我可以使用GetMem和FreeMem但我希望保持字符串的生命周期管理。
我知道问题就在那里,我可以使用TpMyRecord = ^TMyRecord
声明,但我很好奇是否有运行时间方式(尽管我&#39 ; m怀疑它对RTTI的麻烦太多了。)
答案 0 :(得分:3)
这可能有点诡计。这是一个演示程序:
{$APPTYPE CONSOLE}
uses
TypInfo;
type
PMyRecord = ^TMyRecord;
TMyRecord = record
s1: string;
s2: string;
end;
var
SystemNew: function(Size: NativeInt; TypeInfo: Pointer): Pointer;
SystemDispose: procedure(P: Pointer; TypeInfo: Pointer);
function GetSystemNewAddress: Pointer;
asm
MOV EAX, offset System.@New
end;
function GetSystemDisposeAddress: Pointer;
asm
MOV EAX, offset System.@Dispose
end;
var
p: PMyRecord;
typeInfo: Pointer;
begin
ReportMemoryLeaksOnShutdown := True;
@SystemNew := GetSystemNewAddress;
@SystemDispose := GetSystemDisposeAddress;
typeInfo := System.TypeInfo(TMyRecord);
p := SystemNew(TypInfo.GetTypeData(typeInfo).RecSize, typeInfo);
p.s1 := 'foo';
p.s2 := 'bar';
SystemDispose(p, typeInfo);
end.
New
函数是一个内部函数,并从编译器接受特殊处理。当您调用New
时,编译器会发出代码来调用System._New
来传递类型的大小及其类型信息。反过来System._New
使用类型的大小分配内存,然后使用类型信息初始化实例。
上面程序中的代码显示了如何从代码中进行调用。棘手的部分是获得System._New
的地址。这里的代码显示了如何为32位Windows编译器执行此操作。
如果您想致电New
,您还需要致电Dispose
。这也是一种内在的,并且处理得非常相似。上面的代码显示了如何。
不言而喻,这依赖于将来可能会发生变化的实施细节。