Delphi 释放TObjectList时发生访问冲突
我有以下Delphi代码:Delphi 释放TObjectList时发生访问冲突,delphi,free,access-violation,Delphi,Free,Access Violation,我有以下Delphi代码: 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
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;
模块“Vcl50.bpl”中地址4003AB4处的访问冲突。读取地址2980BFFC
我知道访问违规通常是由
但在这里,在我做免费之前,我检查了分配是否已分配。如果我放弃异常处理,我的应用程序将抛出一个“有问题”错误。 分配是一个TObjectList,如果它是一个数组-我怀疑我没有给数组分配长度,但它是一个TObjectList
非常感谢 A
TObjectList
通常负责销毁其内容。在这种情况下,不要释放对象。这将导致在释放TObjectList
时发生访问冲突,因为它试图再次释放包含的对象
对象列表的这种行为可以在其构造函数中控制:
constructor TObjectList.Create(AOwnsObjects: Boolean);
使用此选项可以指定是否希望列表拥有其内容(意味着:当项目从列表中删除或列表被销毁时,它负责销毁该项目)。不带参数的构造函数(您可能使用过)将其设置为true
您可能只需要一个类似于TList
的列表,但用于存储对象。如果是这种情况,请创建如下列表:
Allocations:= TObjectList.Create(False);
但是如果您想要自动销毁行为,那么只需删除for循环。对象列表将销毁您的
TXX\u ALOC
对象。通常,在清除要从一端循环到另一端的列表时
for i := (Allocations.Count - 1) downto 0 do begin
Delete(Allocations.Items[i]);
end
但在这种情况下,如果列表拥有对象(默认情况下是这样),则在销毁容器之前不应释放它们,因为列表会为您这样做。在上面的代码中,如果列表拥有这些对象,那么调用Delete也会释放该对象。有两个选项供您选择 1) 如果希望Delphi在对象从ObjectList中删除时自动释放对象,请创建将aOwnsObjects设置为true的TObjectList。在析构函数simple FreeAndNil中,对象列表本身。这将从列表中删除所有对象并自动释放它们。由于释放ObjectList将自动释放该列表中包含的对象,因此您的代码可能如下所示:
destructor TXX_XXXX.Destroy;
begin
FreeAndNil( Allocations ); //
inherited;
end;
2) 在aOwnsObjects设置为False的情况下创建TObjectList,在这种情况下,您必须自行释放列表中的对象。您的代码可以如下所示:
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;
“但在这里,在我执行free之前,我检查了分配”…请注意,这仅在您不仅调用
free
而且还显式地将引用设置为nil
时才有帮助(或者最好使用FreeAndNil
)Free
不会将引用设置为nil
,这是分配的
检查的内容!既然他没有把它们拿走,那就没那么重要了。但通常是这样。清除列表释放列表中的元素通常是这样的。但是,如果存在更复杂的所有权模型,那么销毁obj可能会导致列表从自身中删除obj。向零的循环也是稍微优化的,所以无论如何使用它都是个好主意。但是我现在将示例代码改为使用Delete
。我还没有遇到过比这更复杂的所有权模型,在这里很难理解它-为什么使用Delete而不是Free。@spspli如果TObjectList拥有它所包含的对象,那么调用Delete
将从列表中删除该项并将其释放。但是,由于列表中对象的计数发生了变化,您必须将循环降到0,否则您将得到错误,因为for循环索引在循环开始时只计算了一次循环中的code>是“过度杀伤力”,因为您正在禁用一个局部变量。只要oObject.Free
就可以了。我相信鲁迪很快就会教你:)即使对局部变量使用FreeAndNil
,也不会伤害IMHO,它的好处是人们不必每次都考虑使用哪一个。有关Free
与FreeAndNil
的讨论,请参见此处: