Delphi 10.3 Rio-是否需要初始化内联声明的记录变量?

时间:2019-03-04 16:57:25

标签: delphi delphi-10.3-rio

我对Delphi 10.3 Rio内联变量声明感到非常兴奋。但是我遇到了一个奇怪的问题,似乎我需要在内联声明后初始化记录:

program Project8;
{$APPTYPE CONSOLE}
{$R *.res}

uses System.SysUtils,classes;

procedure DoEvil;
  //var sr:TSearchRec; //A
begin
  //var sr:= default(TSearchRec); //B
  var sr:TSearchRec; //C
  sr.Name := EmptyStr; //D
  FindFirst('*.*',faAnyFile,sr);
  while sr.Name<>EmptyStr do
  begin
    Writeln(sr.name);
    sr.Name := EmptyStr;
    FindNext(sr);
  end;
end;

begin
  try
     DoEvil;
    { TODO -oUser -cConsole Main : Insert code here }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.

如果我在行上声​​明sr,则代码可以正常工作

  • // A(旧样式声明)或在线
  • // B(带有初始化的内联声明)。

但是如果我在行上声​​明sr

  • // C然后在// D行崩溃,分别在26222行的system.pas中崩溃:

    MOV     ECX,[EDX-skew].StrRec.refCnt    { fetch refCnt                 }
    

例外:

  

异常类$ C0000005,消息为“访问冲突位于   0x0040ac98:读取地址0xfffffff9'。处理Project8.exe(18928)

我将从地址-6假设,字符串成员sr.name未初始化且为nil。

为了完整起见,Delphi是新的10.3版本1: Embarcadero®Delphi 10.3版本26.0.33219.4899-已安装更新1

1 个答案:

答案 0 :(得分:6)

我在CPU窗口中查看了一下,发现了一些奇怪的地方。

如果我使用旧式var块(您的版本// A),则CPU窗口将显示对System._InitializeRecord的调用,如其应有的那样。一切正常。

如果我将内联声明与Default()(您的版本// B)一起使用,则会删除本地记录,然后使用System._FinalizeRecord进行最终确定,然后再次删除 。那是很奇怪和没用的,但是可以。

但是,如果我使用的是您的版本// C,则不执行任何操作来初始化记录:不删节,不_InitializeRecord。当我测试您的代码时,事情确实起作用了,但是我可能很幸运。

所以这显然是一个错误。请报告给Embarcadero Quality Portal


猜测,这是在测试默认构造函数,默认析构函数和重载的赋值运算符(但随后将其删除并推迟到下一个版本)时对编译器所做的其余更改。其中一些变化相当死脑筋(例如B版本中的nilling,finalization和nilling),我想其中一些变化被遗忘了。

更新

很明显,这已经报告给QP: