2011-08-16 38 views
4

我有以下的Delphi代码时:访问冲突释放TObjectList

destructor TXX_XXXX.Destroy; 
var 
i: Integer; 
begin 
    if Assigned(Allocations) then 
    begin 
    for i:=0 to (Allocations.Count - 1) do 
    begin 
     try 
     TXX_ALOC(Allocations.Items[i]).Free; 
     except on Ex:Exception do 
     begin 
     OutputDebugString(PChar('Exception Error Message '+ Ex.Message)); 
     end; 
     end; 
    end; 

     // Above code works well - no exception 

     try 
    FreeAndNil(Allocations); {Exception Here} 
    except on E:Exception do 
    begin 
     OutputDebugString(PChar('Exception in xxxxxxxxx.pas'+E.Message)); 
    end; 
    end; 
    end; 
    inherited; 
end; 

访问冲突在模块地址4003AB4 'Vcl50.bpl'。读地址2980BFFC

我知道通常

  1. 自由一些对象导致访问冲突之前
  2. 使用一些对象,而无需初始化

但在这里我之前已经被释放做免费的,我检查Allocations分配。如果我放弃异常处理,我的应用程序会抛出一些错误的错误。 Allocations是一个TObjectList,如果它是一个数组 - 我会怀疑我没有给该数组分配一个长度,但它是一个TObjectList。

非常感谢!

+5

“但在这里之前,我做了免费的,我检查分配分配” ......注意,如果你不仅调用'Free'也设置了这不仅有助于明确引用“nil”(或更好地使用FreeAndNil)。 'Free'不会将引用设置为'nil',这就是'Assigned'检查的内容! – jpfollenius

回答

18

A TObjectList通常负责销毁其内容。在这种情况下不要释放你的物体。这会在释放TObjectList时导致访问冲突,因为它会尝试再次释放包含的对象。

对象列表的这种行为可以在其构造控制:

用这个来指定,如果你想要列表自己它的内容(指:它需要销毁的产品负责当它从列表中删除或列表被销毁时)。不带参数的构造函数(您可能使用过)将其设置为true

您可能只是想要一个列表,如TList,但用于存储对象。如果是这样的话,那么在建立名单如下:

Allocations:= TObjectList.Create(False); 

但是如果你想自动破坏行为则只是删除了for循环。对象列表将破坏您的TXX_ALOC对象。

7

一般而言,结算清单,当你想从结束循环开始即

for i := (Allocations.Count - 1) downto 0 do begin 
    Delete(Allocations.Items[i]); 
end 

但在TObjectList情况下,如果列表拥有对象(它在默认情况下),你不应该在他们自由摧毁容器,因为清单将为你做。在上面的代码中,如果列表拥有对象,那么调用Delete也会释放对象。

+0

由于他没有删除它们,所以没有那么重要。但通常你会这样做。 –

+1

清除列表<>释放列表中的元素 – jpfollenius

+0

通常是。但是,如果存在更复杂的所有权模型,则销毁obj可能会导致列表从其自身删除obj。循环趋向于零也是最优化的,所以恕我直言,无论如何都使用它是个好主意。但是我现在改变了示例代码来使用'Delete'。 – ain

3

有你的2个选项...

1)创建TObjectList室内用,如果你想德尔福自动释放的对象,当他们从链表类删除设置为true aOwnsObjects。并且在你的析构函数中简单的FreeAndNil ObjectList本身。这会从列表中删除所有对象并自动释放它们。由于释放的链表类会自动释放包含在该列表中的对象,您的代码然后可以像:

destructor TXX_XXXX.Destroy; 
begin 
    FreeAndNil(Allocations); // 
    inherited; 
end; 

2)创建TObjectList室内用设置为False aOwnsObjects,在这种情况下,你将不得不照顾自己释放列表中的对象。然后,您的代码可能是这个样子:

destructor TXX_XXXX.Destroy; 
var 
    i  : Integer; 
    oObject : TObject; 
begin 
    if Assigned(Allocations) then 
    begin 
    for i:= Pred(Allocations.Count) downto 0 do 
    begin 
     // Get a reference to the Object 
     oObject := TXX_ALOC(Allocations.Items[i]); 
     // Remove the object from the object list 
     Allocations.Delete(i); 
     // Free the Object 
     FreeAndNil(oObject); 
    end; 
    end; 

    FreeAndNil(Allocations); 
    inherited; 
end; 
+1

循环中的'FreeAndNil(oObject);'是“矫枉过正”,因为你无法在本地变量。只需'oObject.Free'就可以。我相信Rudy很快会教你:) – ain

+0

即使对局部变量使用FreeAndNil也没有什么坏处,恕我直言,它有一个好处就是不用考虑每次使用哪一个。 – jpfollenius

+0

查看这里讨论'免费'vs'FreeAndNil':http://stackoverflow.com/questions/3159376/which-is-preferable-free-or-freeandnil – jpfollenius