2017-08-14 151 views
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時。

怎麼回事?

回答

3

這似乎是一個編譯器缺陷:

#RSP-18833: Capture by closure corrupts local variable used in nested method

一種解決方法是在匿名方法使用的第二可變捕獲:

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;