Delphi TStringList Free导致异常

时间:2013-03-16 03:24:39

标签: delphi delphi-3

考虑这个简短的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

2 个答案:

答案 0 :(得分: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,这可以帮助您自己解决此问题。)

答案 1 :(得分:-3)

问题的答案:

  1. 为什么field_list <> NIL Delphi不初始化本地对象。有关详细信息,请参阅:Why doesn't object default to nil?Are delphi variables initialized with a value by default?

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

  3. 如果它不是NIL它是什么? 指针无效。

  4. 如果它未分配而不是NIL我怎么知道是否Free呢? 您需要重新组织代码(见下文)。 Assigned函数没有告诉我:if Assigned(an_object)等同于if an_object = NIL 为nil(未分配)指针或过程变量分配测试。 &lt; - 来自Delphi 3文档。 未初始化本地对象没有被分配NIL所以Assigned(an_object)返回TRUE,如果an_object是本地和从未使用(分配NIL是使用对象)。

  5. 因为过程本地的对象没有初始化为NIL,所以我修改了分配NIL本地所有本地对象的问题的代码。我在例程的最开始做这些任务,以便免费 如果永远不会创建本地对象,则不会输出错误。我还展示了原始问题中遗漏的错误跟踪代码:

    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`中释放它们 即使在创建之前存在运行时错误,块也不会引发错误。