当在嵌套的方法中被访问时,闭包捕获破坏了局部变量。

8

我已经将这个问题简化为:

program Project1;
{$APPTYPE CONSOLE}

uses
  SysUtils, Threading;

procedure Foo(AString: string);
var
  LTask : ITask;
  capturedString : string;
  procedure Nested;
  begin
    try
      WriteLn('Nested : ' + capturedString); { ! EIntOverflow (Win32) here }
    except on E : Exception do
      WriteLn(E.Message);  
    end; 
  end;
begin
  capturedString := AString;
  WriteLn('Local : ' + capturedString);
  Nested;
  LTask := TTask.Create(
    procedure
      procedure AnonNested;
      begin
        WriteLn(capturedString); { Removing this eliminates the problem }
      end;
    begin
    end);
end;

begin
  Foo('foo');
  ReadLn;
end.

这里的`capturedString`变量在嵌套方法内访问时会出现损坏。Win32编译会引发`EIntOverflow`,Win64编译会写出(损坏的)空字符串 - 通过一些操作可以激发任何构建中的AV或其他异常,但在所有情况下,当进入`Nested`过程时,对局部变量的引用都被破坏了。
这似乎只会在闭包中捕获`capturedString`时发生。
出了什么问题?
1个回答

3
这似乎是一个编译器错误,在10.2中已经解决:
#RSP-18833: 闭包捕获破坏了嵌套方法中使用的局部变量
解决方法是在匿名方法中使用第二个变量进行捕获。
procedure Foo(AString: string);
var
  LTask : ITask;
  capturedString, s2 : string;
  procedure Nested;
  begin
    try
      WriteLn('Nested : ' + capturedString);
    except on E : Exception do
      WriteLn(E.Message);  { !!! }
    end; 
  end;
begin
  capturedString := AString;
  s2 := capturedString;
  WriteLn('Local : ' + capturedString);
  Nested;
  LTask := TTask.Create(
    procedure
      procedure AnonNested;
      begin
        WriteLn(s2); { Capture another variable }
      end;
    begin
    end);
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接