代码之家  ›  专栏  ›  技术社区  ›  Luiz Alves

制作对象的副本以供以后使用

  •  0
  • Luiz Alves  · 技术社区  · 6 年前

    我有一个具有以下类的组件:

    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 回复  |  直到 6 年前
        1
  •  5
  •   Remy Lebeau    6 年前

    这个 TObjectList.OwnsObjects 默认情况下,属性为True。 TObjectList inherits Assign() from TList ,默认情况下,它只是从源列表复制指针。

    所以,你最终得到了两个 Tobject列表 对象都“拥有”相同的对象集,因此当一个列表尝试释放另一个列表已释放的相同对象时,您将获得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;