制作要在以后使用的对象的副本

时间:2018-06-04 22:08:11

标签: delphi object

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

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;

1 个答案:

答案 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;