当函数中出现异常时,TStrings返回为"无法访问的值"

Lar*_*ars 5 delphi

有人可以帮助我解释为什么在底层函数中引发异常时,TStrings被返回为"无法访问的值"吗?

function GetStrings():TStrings;
begin
  result := TStringList.Create;
  try
    raise exception.Create('Error Message');
  except
    FreeAndNil(result);
    raise
  end;
end;

procedure TFormMain.Button1Click(Sender: TObject);
var
  S : TStrings;
begin
  try
    S := GetStrings;
    try
      //Do awesome stuff
    finally
      FreeAndNil(S)
    end;
  except
    //Debug watch: S = "Inaccessible value"
    Assert(S = nil, 'Assertion failure, S should be nil'); 
  end;
end;
Run Code Online (Sandbox Code Playgroud)

GetStrings如果我FreeAndNil(result);在重新引发异常之前没有调用,该函数也会返回"无法访问的值" .但是,我手上也有内存泄漏:-O

Dav*_*nan 6

try
  S := GetStrings; 
  try
    //Do awesome stuff
  finally
    FreeAndNil(S)
  end;
except
  //Debug watch: S = "Inaccessible value"
  Assert(S = nil, 'Assertion failure, S should be nil'); 
end;
Run Code Online (Sandbox Code Playgroud)

这是执行的顺序:

  1. 由于S是局部变量,因此在初始化之前,其值是不确定的.这是该代码开始执行时的状态.
  2. GetStrings函数被调用.
  3. 提出异常GetStrings.这意味着GetStrings不会将执行返回给调用者,因此具有S从未分配的结果.
  4. finally块未执行,因为从未尝试过它.
  5. 接下来,except块执行,并S具有不确定的值,这是您观察到的.

实际上,编译器应警告(W1036)Sexcept块中引用它时可能尚未初始化.但它似乎无法做到这一点,这是相当可悲的.

如果您希望能够S在您的except区块中引用,您将需要将其嵌入到区域中try/finally.

S := GetStrings; 
try
  try
    //Do awesome stuff
  except
    //Do stuff with S
    Assert(S <> nil);
  end;
finally
  FreeAndNil(S)
end;
Run Code Online (Sandbox Code Playgroud)

另一种思考方式S是只在分配S的代码和销毁对象的代码之间有意义.结果是try/except必须嵌套在内部try/finally,如果except块将能够引用该对象.

  • @DavidSchwartz,`Result`是它出现的函数上下文中的局部变量.一般来说,它不是*函数结果在返回时赋值的变量的别名.(这样的变量不一定存在!)在`GetStrings`中分配给`Result`不会立即修改调用者中的`S`.相反,`S`仅在`GetStrings`返回后分配.*如果`GetStrings`抛出,则它不会返回*,因此在这种情况下不会分配`S`. (3认同)
  • 你能把S:= nil; 试试S:= GetStrings; ?? (2认同)