0

I have an ObjectList that is populated. Then details changed in the objects. Now I need to free the ObjectList but when I do it also frees the objects in the list. How can I free this list without freeing the objects themselfs?

Example code:

{Gets starting cards and put them into the correct rows}
//***************************************************************************
procedure TFGame.GetStartingCards;
//***************************************************************************
const
  ManaTypes : array [0..3] of string = ('Lava','Water','Dark','Nature');
var
   i: integer;
   z:integer;
   Cards: TObjectList<Tcard>;
begin
  Cards := TObjectList<TCard>.Create;
  z:=0;
  {add all tcards (Desgin ) to this list in order Lava,water,dark,nature }
  cards.Add(cardLava1);
  cards.Add(cardlava2);
  cards.Add(cardlava3);
  cards.Add(cardlava4);
  cards.Add(cardwater1);
  cards.Add(cardwater2);
  cards.Add(cardwater3);
  cards.Add(cardwater4);
  cards.Add(carddark1);
  cards.Add(carddark2);
  cards.Add(carddark3);
  cards.Add(carddark4);
  cards.Add(cardnature1);
  cards.Add(cardnature2);
  cards.Add(cardnature3);
  cards.Add(cardnature4);
 //get data from DB
  for i := 0 to Length(ManaTypes) - 1 do
  begin
    with adoquery1 do
    begin
      close;
      sql.Clear;
      sql.Add('SELECT TOP 4 * FROM Cards WHERE Color = "'+ManaTypes[i]+'" ORDER BY Rnd(-(1000*ID)*Time())');
      open;
    end;

      {return the result of everything for giving mana type.. }
     if adoquery1.RecordCount = 0 then
        Showmessage('Error no cards in db');
     adoquery1.First;

     while not adoquery1.Eof do
     begin
        cards[z].Cname := adoquery1.FieldByName('Name').AsString;
        cards[z].Ccost := adoquery1.Fieldbyname('Cost').AsInteger;
        cards[z].Ctext := adoquery1.FieldByName('Text').AsString;
        cards[z].Ccolor := adoquery1.FieldByName('Color').AsString;
        cards[z].Cinplay := false; //in the play area
        if adoquery1.fieldbyname('Power').asstring <> '' then
            cards[z].Cpower := adoquery1.FieldByName('Power').AsInteger;
        if adoquery1.fieldbyname('Def').asstring <> '' then
            cards[z].Cdef := adoquery1.FieldByName('Def').AsInteger;
        if adoquery1.FieldByName('Type').AsString = 'Spell' then
           cards[z].Cspell := true
        else
           cards[z].Cspell := false;
        if adoquery1.FieldByName('Target').AsString = 'yes' then
            cards[z].SetTargetTrue
        else
            cards[z].settargetfalse;

        //based on color change background
        cards[z].Background.LoadFromFile(format('%s\pics\%s.png',[maindir,cards[z].Ccolor]));
       adoquery1.Next;
       cards[z].repaint;
       z:=z+1;
     end;

  end;
 //cards.Free; if i free this it removes all the cards added to it..
end;
4

1 回答 1

4

The constructor for TObjectList<T> receives a parameter named AOwnsObjects which specifies who is to be responsible for freeing the objects. If you pass True then the list has that responsibility. Otherwise, the responsibility remains with you.

constructor Create(AOwnsObjects: Boolean = True); overload;

The parameter has a default value of True and I presume that you are calling the constructor without specifying that parameter. Hence you get the default behaviour – the list owns its members.

The documentation says it like this:

The AOwnsObjects parameter is a boolean that indicates whether object entries are owned by the list. If the object is owned, when the entry is removed from the list, the object is freed. The OwnsObjects property is set from the value of this parameter. The default is true.

Now, if you want this particular list instance not to free its members, then there is little to be gained from using TObjectList<T>. You may as well use plain old TList<T>.

于 2013-11-01T14:35:12.353 回答