考虑这个简短的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,
field_list <> NIL
? NIL
的对象? NIL
它是什么? NIL
我怎么知道是否Free
呢? Assigned
函数没有告诉我:if Assigned(an_object)
等同于if an_object = NIL
答案 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)
问题的答案:
为什么field_list <> NIL
?
Delphi不初始化本地对象。有关详细信息,请参阅:Why doesn't object default to nil?和Are delphi variables initialized with a value by default?
是未初始化为NIL
的对象? 全局对象:是的。本地对象:否。
如果它不是NIL
它是什么? 指针无效。
如果它未分配而不是NIL
我怎么知道是否Free
呢? 您需要重新组织代码(见下文)。
Assigned
函数没有告诉我:if Assigned(an_object)
等同于if an_object = NIL
。 为nil(未分配)指针或过程变量分配测试。 &lt; - 来自Delphi 3文档。
未初始化本地对象没有被分配NIL所以Assigned(an_object)
返回TRUE,如果an_object是本地和从未使用(分配NIL是使用对象)。 强>
因为过程本地的对象没有初始化为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_list
或some_other_object
,则会将其释放。他们在一开始就分配了NIL,因此在'try ... finally`中释放它们
即使在创建之前存在运行时错误,块也不会引发错误。