我有一个包含以下类的组件:
TResp=Class
...
TRespostasPendentes = class(TObjectList)
private
fSaldoAPagar : Double;
function GetSaldoRestante : Double;
function GetTotalPago : Double;
function GetTotalDesconto : Double;
protected
procedure SetObject (Index: Integer; Item: TResp);
function GetObject (Index: Integer): TResp;
public
function Add (Obj: TResp): Integer;
procedure Insert (Index: Integer; Obj: TResp);
property Objects [Index: Integer]: TResp
read GetObject write SetObject; default;
property SaldoAPagar : Double read fSaldoAPagar write fSaldoAPagar ;
property TotalPago : Double read GetTotalPago ;
property TotalDesconto : Double read GetTotalDesconto ;
property SaldoRestante : Double read GetSaldoRestante ;
end;
我需要在TRespostasPendentes
中复制对象,以便在释放后使用。
原始类不实现Assign()
方法。
我尝试了下一个代码,但在释放副本时出现访问冲突。
我做错了什么?
我无法更改原始类。
RespostasPendentes:=TRespostasPendentes.Create;
//Here I fill some properties of RespostasPendentes
RP:=TRespostasPendentes.Create;
try
RP.Assign(RespostasPendentes);
RespostasPendentes.Free;
finally
RP.Free; -->Access Violation
end;
默认情况下,TObjectList.OwnsObjects
属性为 True。TObjectList
继承Assign()
自TList
,默认情况下,它只是从源列表中复制指针。
因此,您最终会得到两个TObjectList
对象,它们都"拥有"同一组对象,因此当一个列表尝试释放另一个列表已经释放的相同对象时,您将获得 AV。
要防止第一个列表释放对象,您需要:
-
将对象指针复制到第二个列表后,将第一个列表的
OwnsObjects
设置为 False。RespostasPendentes := TRespostasPendentes.Create; // ... RP := TRespostasPendentes.Create(False); // <-- False initially in case Assign() fails... try RP.Assign(RespostasPendentes); RespostasPendentes.OwnsObjects := False; // <-- add this RP.OwnsObjects := True; // <-- take ownership of the copied pointers RespostasPendentes.Free; // use RP as needed... finally RP.Free; end;
-
Extract()
第一个列表中的对象指针,使其放弃所有权而不释放对象,然后将指针添加到第二个列表。RespostasPendentes := TRespostasPendentes.Create; // ... RP := TRespostasPendentes.Create; try RP.Capacity := RespostasPendentes.Count; while RespostasPendentes.Count > 0 do begin Obj := RespostasPendentes.Objects[0]; RespostasPendentes.Extract(Obj); // <-- remove ownership try RP.Add(Obj); // <-- take ownership except Obj.Free; raise; end; end; RespostasPendentes.Free; // use RP as needed... finally RP.Free; end;