2013-03-16 37 views
4

考虑这短短的Delphi程序:当我运行这德尔福的TStringList免费导致异常

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; 

,德尔福3,其中x = '',因此永远不会创建FIELD_LIST,

  1. 为什么field_list <> NIL
  2. 是未初始化为NIL的对象?
  3. 如果不是NIL这是什么?
  4. 如果是未分配而不是NIL我怎么知道是否要Free呢?该Assigned功能并没有告诉我:if Assigned(an_object)if an_object = NIL
+0

绝对没有必要在免费之前检查指定的参考。免费已经这样做,如果分配调用Destroy。这就是为什么你不应该叫Destroy – 2013-03-16 03:53:19

+1

没有编译器警告你这个代码?切勿忽略编译器诊断。 – 2013-03-16 04:34:03

+0

此答案将对您有所帮助:http://stackoverflow.com/questions/8548843/why-should-i-not-use-if-assigned-before-using-or-freeing-things/8550628#8550628 – 2013-03-16 07:33:17

回答

8

等价的问题是if x = '',将finally发生反正。由于field_list仅在x <> ''时才被初始化,因此它是一个随机内存位置,因为它是一个未初始化的局部变量。随机值允许调用field_list.free,因为它不等于nil。 (德尔福未初始化的局部变量(这些函数或过程)中声明。)

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,这会帮助你解决这个你自己。)

+0

那里不需要'if field_list <> NIL'。 'TObject.Free'已经为此测试 - 实际上它是它的全部目的。所有这些都是说'if field_list <> NIL then field_list <> NIL then field_list.Destroy;'见http://docwiki.embarcadero.com/Libraries/XE2/en/System.TObject.Free – 2013-03-16 03:59:55

+0

@Gerry:很好的接收。我错过了在两个代码片段中删除它们。谢谢。 :-) – 2013-03-16 04:17:23

+1

“Delphi 3没有初始化局部变量”没有Delphi的版本。 – 2013-03-16 07:34:31

0

是局部对象过程或函数不被初始化为NIL我修改了代码如下:

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

我也可以把try..finally其周围只是字符串列表创建和代码但我喜欢保护整个程序;例如,如果它是try..except块,我担心if x测试可能会失败。 Delphi不会将局部变量对象初始化为零。

+0

初始化为零会浪费。在if里面移动try/finally。或者更好的是,在开始时将if转换为警卫权:如果x =''则退出;此外,这不回答问题。 – 2013-03-16 22:45:49

+0

或者我可以把try..finally块放在字符串列表create和{do some stuff ..}代码中,但我喜欢保护整个过程;例如,如果它是try..except块,我担心if x测试可能会失败。 Delphi不会将局部变量对象初始化为零。 – 2013-03-17 06:33:05

+1

是的,我第一次看了那篇文章。使用非标准的try/finally只会让读者不得不更加认真地考虑代码。不要这样做。 – 2013-03-17 07:53:02