记录中的接口字段

jpf*_*ius 3 delphi delphi-xe

我可以依赖这样一个事实,即记录中的接口字段是否始终初始化为nil

TMyRec = record  
  FGuard : IInterface;
  FObject : TObject;
  procedure CheckCreated;
end;
Run Code Online (Sandbox Code Playgroud)

这将允许我写:

procedure TMyCheck.CheckCreated;
begin
if (FGuard = nil) then
  begin
  FObject := TObject.Create;
  FGuard := TGuard.Create (FObject);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

(用于自动终身管理)

我知道接口字段已初始化为,nil但是当包含在记录中时也是如此?

Arn*_*hez 9

是的,你可以依靠它.

所有参考计数变量:

  • 字符串;
  • 动态数组;
  • 变体;
  • 接口;
  • 包含这些变量的嵌套记录.

如果你使用或动态数组 - 甚至在堆栈本地,则初始化为nila .当然,如果你使用普通或使用指针,你必须自己初始化它(例如使用a ).recordNewGetMemFillChar

如果您很好奇,则会对System.pas的以下过程进行隐藏调用:

procedure _InitializeRecord(p: Pointer; typeInfo: Pointer);
Run Code Online (Sandbox Code Playgroud)

这会将所有引用计数变量内存填充为0,但不会设置其他成员record.实际上,在一个class实例中,整个字段内存初始化为0,包括所有成员 - 对于a record,初始化仅用于引用计数类型.

请注意,在某些情况下,我发现如果您使用object类型而不是record- 至少在Delphi 2009-2010下,这种初始化没有正确生成.因此,如果您的代码有一些object类型声明,您可以更好地切换到record(和松散的继承),或显式调用FillChar.

如果您很好奇,这是我在asm中编写的优化版本 - 可在我们的增强型RTL中找到.

procedure _InitializeRecord(p: Pointer; typeInfo: Pointer);
// this procedure is called at most object creation -> optimization rocks here!
asm
        { ->    EAX pointer to record to be initialized }
        {       EDX pointer to type info                }
        MOVZX   ECX,[EDX+1]                  { type name length }
        PUSH    EBX
        PUSH    ESI
        PUSH    EDI
        MOV     EBX,EAX                     // PIC safe. See comment above
        LEA     ESI,[EDX+ECX+2+8]           { address of destructable fields }
        MOV     EDI,[EDX+ECX+2+4]           { number of destructable fields }
@@loop:
        mov edx,[esi]    // type info
        mov eax,[esi+4]
        mov edx,[edx]
        add esi,8
        add eax,ebx      // data to be initialized
        movzx ecx,[edx]  // data type
        cmp ecx,tkLString
        je @@LString
        jb @@err
        cmp ecx,tkDynArray
        je @@DynArray
        ja @@err
        jmp dword ptr [ecx*4+@@Tab-tkWString*4]
        nop; nop; nop // align @@Tab
@@Tab:  dd @@WString,@@Variant,@@Array,@@Record
        dd @@Interface,@@err
@@LString:
@@WString:
@@Interface:
@@DynArray: // zero 4 bytes in EAX
        dec edi
        mov dword ptr [eax],0
        jg @@loop
        POP     EDI
        POP     ESI
        POP     EBX
        RET
@@Variant: // zero 16 bytes in EAX
        xor ecx,ecx
        dec edi
        mov [eax],ecx
        mov [eax+4],ecx
        mov [eax+8],ecx
        mov [eax+12],ecx
        jg @@loop
        jmp @@exit
@@err:
        MOV     AL,reInvalidPtr
        POP     EDI
        POP     ESI
        POP     EBX
        JMP     Error
@@Array:
@@Record: // rarely called in practice
        mov ecx,1
        call _InitializeArray
        dec edi
        jg @@loop
@@exit:
        POP     EDI
        POP     ESI
        POP     EBX
end;
Run Code Online (Sandbox Code Playgroud)