4

考虑这个简短的 Delphi 过程:

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list: TStringList;
begin
  try
    if x <> '' then begin
      field_list := TStringList.Create;
      {do some stuff with field_list}
    end;
  finally
    if field_list <> NIL then 
    begin
      field_list.Free;
    end;
  end;
end;

当我在 Delphi 3 中使用 x = '' 运行它时,永远不会创建 field_list,

  1. 为什么field_list <> NIL
  2. 对象没有初始化为NIL?
  3. 如果不是NIL,那是什么?
  4. 如果它没有分配而不是NIL我怎么知道Free它是否分配?Assigned函数没有告诉我:if Assigned(an_object)相当于if an_object = NIL
4

2 回答 2

8

问题是,if x = ''无论如何finally都会发生。由于field_list仅在 时初始化x <> '',因此它是该点之前的随机内存位置,因为它是未初始化的局部变量。随机值允许field_list.free调用 ,因为它不等于nil。(Delphi 不初始化局部变量(那些在函数或过程中声明的变量)。)

var
  somevar: sometype;    
begin
  // at this point, somevar is just a chunk of memory that
  // holds whatever happens to be in that chunk
  somevar := nil;         // now somevar = a specific value you can test

  // other code
end;

如果您正确构建代码,则不必测试<> nil(正如其他人在评论中指出的那样)。

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list  : TStringList;
begin
  if x <> '' then 
  begin
    field_list := TStringList.Create;
    try
      {do some stuff with field_list}
    finally
      field_list.Free;
    end;
  end;
end;

(如果您打开提示和警告,编译器会告诉您field_list may not have been initialized,这将帮助您自己解决这个问题。)

于 2013-03-16T03:31:34.003 回答
-3

问题的答案:

  1. 为什么field_list <> NILDelphi 不初始化本地对象。有关更多详细信息,请参阅:为什么对象不默认为零?并且默认情况下是否使用值初始化delphi变量?

  2. 对象没有初始化为NIL? 全局对象:是的。本地对象:没有。

  3. 如果不是NIL,那是什么?无效的指针。

  4. 如果它没有分配而不是NIL我怎么知道Free它是否分配?您需要重新组织您的代码(见下文)。Assigned函数没有告诉我:if Assigned(an_object)相当于if an_object = NIL. 为 nil(未分配)指针或过程变量分配测试。<--来自 Delphi 3 文档。未初始化的本地对象未分配 NIL,因此Assigned(an_object)如果 an_object 是本地的并且从未使用过(分配 NIL 正在使用该对象),则返回 TRUE。

因为过程的本地对象未初始化为 NIL,所以我修改了问题中的代码,将所有本地对象分配给 NIL。我在例程的一开始就进行这些分配,这样如果从未创建本地对象,Free 就不会出错。我还展示了原始问题中遗漏的错误跟踪代码:

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list: TStringList;
  some_other_object: TAnotherObject;
begin
  try
    try
      field_list := NIL;
      some_other_object := NIL;
      if x <> '' then begin
        field_list := TStringList.Create;
        {do some stuff with field_list}
      end;
      {...}
      some_other_object := TSomeOtherObject.Create;
      {...}
    except
      On E : Exception do begin
        ErrorTrackingRoutine(unit_name, name, 'FieldListFillFromDefault', E.message);
      end;
    end;
  finaly
    field_list.Free;
    some_other_object.Free;
  end;
end;

整个例程受保护try...except。如果field_listsome_other_object被创建,它将被释放。它们在一开始就被分配为 NIL,因此即使在创建它们之前存在运行时错误,在“try...finally”块中释放它们也不会引发错误。

于 2013-03-16T21:51:38.443 回答