创建对象的副本以供以后使用



我有一个包含以下类的组件:

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;
    

最新更新