编译器警告 "返回值可能未定义"

12

我经常使用以下代码:

function GetNumber(Handle : THandle) : Integer;
begin
FLock.BeginRead;
try
  if FMap.TryGetValue(Handle, Object) then
    raise EArgumentException.Create('Invalid handle');
  Result := Object.Number;
finally
  FLock.EndRead;
end;
end;

很不幸,编译器对所有这些方法都发出了警告:

[DCC Warning] Unit.pas(1012): W1035 Return value of function 'GetNumber' might be undefined
我知道这个警告,但在这种情况下我完全看不出任何原因。或者是否有一种场景我没有察觉到,会导致返回一个未定义的结果值?我理解在 try..except 的情况下发出警告,但是对于 try..finally 对我来说就没有意义。
问题:
  • 这个警告是否有任何原因?
  • 如何摆脱它(将Result := Object.Number行移出锁定不是一个选项,并且我想避免在每个函数的顶部编写完全不必要的Result := 0行)?
谢谢!

3
很不幸,我不得不处理这个问题好几次。你会在我的代码中发现一些 Result := X; // 避免编译器警告 ,其中一些是由于编译器版本之间的更改而有条件地编译的。Embarcadero 应该修复这个错误,因为它很烦人! - Cosmin Prund
3个回答

5

这个警告有什么原因吗?

我看不出来有什么原因,但是它是由于raise而存在的。

我该如何消除它(将Result:= Object.Name行移出锁定不是一个选项,我想避免在每个函数顶部编写完全不必要的Result:= 0行)

将raise语句移到自己的过程中。

function GetNumber(Handle : THandle) : Integer;
    procedure InvHandle;
    begin
        raise EArgumentException.Create('Invalid handle');
    end;
begin
    FLock.BeginRead;
    try
        if FMap.TryGetValue(Handle, Object) then
            InvHandle;
        Result := Object.Number;
    finally
        FLock.EndRead;
    end;
end;

2
这并不是raise的问题。编译器早已认识到,一个带有raise的代码路径可以使程序员免除对返回值的赋值义务。尝试编译OP的代码,但将Try/Finally删除! - David Heffernan
@David - 没有try..finally时没有编译器警告。但我认为删除try..finally块不是解决手头问题的好方法。将raise语句移动也可以消除警告,因此我猜测编译器中的错误与在try..finally块内使用raise有关。 - Mikael Eriksson
5
@Mickael 我并不是在建议移除 try/finally!我的观点是这显然是一个编译器的 bug。 - David Heffernan
@David - 你怎么确定这是try/finally的问题而不是raise的问题?移除其中任何一个都可以解决警告吗?! - Lieven Keersmaekers
@lieven,如果没有raise,那就是一个根本不同的问题。无论如何,出了问题。 - David Heffernan
@David:哇!!移除 try/finally 就会移除锁的资源保护!第一个异常,你就永远无法解锁。 - Disillusioned

3
那是一个编译器错误。如果删除try/finally,则不会发出警告。编译器长期以来一直能够认识到raise使程序员免除了分配返回值的义务。由于某种原因,try/finally似乎会混淆它的分析。
再想一想,也许这不是编译器的错误。如果finally块中的代码阻止了异常传播怎么办?显然没有except处理程序,但我相信System或SysUtils单元中的异常支持例程之一可能能够阻止异常进一步发展。

但我相信系统或SysUtils单元中的异常支持程序之一可能能够阻止异常进一步发展。您为什么这样认为?他们为什么要这样做? - jpfollenius
@Smasher,我现在也不太确定了。我曾经认为AcquireExceptionObject可以停止异常的进程,但我现在不这么认为了。 - David Heffernan
3
如果没有 raise 语句,而只有 try …; Result := …; finally … end;,即使在到达 Result 赋值语句之前仍可能出现异常,也不会出现“返回值未定义”警告。 - Andriy M
移除try/finally将会移除锁的资源保护!第一个异常就会导致无法解锁。另外,如果finally能够阻止异常的传播,则手头上存在着更为严重的问题! - Disillusioned
6
@Craig,我担心你完全误解了我的帖子重点,并浪费了你的有价值的下降投票。当然我不是在主张OP删除try/finally。那样做是疯狂的。我想表达的是try/finally和编译器警告之间的交互作用。即使try/finally对返回值的设置没有影响,但在没有try/finally时不会发出警告。 - David Heffernan

-2

一个任务

Result := ...;

缺少finally块。


需要额外的结果用于 except 块,而不是 finally 块。 - Disillusioned

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