Delphi - Generics free
Asked Answered
P

1

8

Having the following generics class

 TTuple<T1, T2> = class
  protected
    fItem1: T1;
    fItem2: T2;
  public
    constructor Create; overload;
    constructor Create(Item1: T1; Item2: T2); overload;
    destructor Destroy; override;

    property Item1: T1 read fItem1 write fItem1;
    property Item2: T2 read fItem2 write fItem2;
  end;

constructor TTuple<T1, T2>.Create;
begin
  inherited;
end;

constructor TTuple<T1, T2>.Create(Item1: T1; Item2: T2);
begin
  fItem1 := Item1;
  fItem2 := Item2;
end;

destructor TTuple<T1, T2>.Destroy;
begin
  inherited;
end;

and used in a manner like:

x := TTuple<TObjectList<TMyObjects>, Integer>.Create;

I need to free fitem1 manually. How can I free the fItem1 inside the destructor?

Priestess answered 3/3, 2018 at 10:41 Comment(3)
Just write T1: class instead of T1 and you got the trick. In that way you have a "less generic" generic because T1 can only be a class type; since the compiler is aware of this fact, you'll be able to call FreePoliticking
You can learn a lot of tricks for using Generics in Delphi looking at the source of System.Generics.Collections. TObjectList<T> and TObjectDictionary<TKey,TValue> will show you how the RTL uses the techniques outlined in @AndreiGalatyn response.Begrime
What does this class give you? It seems to offer an extra later of complexity for no benefits that I can discern. Or is it just an illustration?Separable
G
9

In the definition of TTuple there is no restrictions on type of T1,T2. That is why you can't call destructor, because it can be any type, double/integer etc. Direct answer to your question:

  PObject(@fItem1).DisposeOf;

But it will work properly only when T1 is class. Proper solution is to define TTuple with restrictions on type:

TTuple<T1: class; T2> = class

Then you can free it in normal way:

fItem1.Free

To make it in Delphi-like style you can create two generic classes:

TTuple<T1,T2> = class
...
end;

TObjectTuple<T1: class; T2> = class<TTuple<T1,T2>>
  ...
  property OwnsKey: boolean;
end;

destructor TObjectTuple<T1,T2>.destroy;
begin
  if OwnsKey then
    FItem1.DisposeOf;
end;

For example look how it is implemented in

TObjectList<T: class>
Grapery answered 3/3, 2018 at 11:6 Comment(1)
Is this safe? if PTypeInfo(TypeInfo(T1)).Kind = tkClass then PObject(@FItem1).DisposeOf;Begot

© 2022 - 2024 — McMap. All rights reserved.