我有一个包含以下类的组件:
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;
答案 0 :(得分:5)
默认情况下,TObjectList.OwnsObjects
属性为True。 TObjectList
inherits Assign()
from 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;