Dowemo
0 0 0 0


Question:

I want to know the best way to free a TList filled with record.

I have the following record:

type
TPkBill = record
    PkBill: integer;
    Constructor Create(c_PkBill: integer);
constructor TPkBill.Create(c_PkBill: integer);
begin
    PkBill := c_PkBill;
end;

I create the list and fill it with the record:

procedure TfrmProject.lvBillDblClick(Sender: TObject);
var   
   i, iCount: integer;
   item: TListItem;
   oPkBill: TPkBill;
   lstPkBill: Tlist;
begin
   iCount := 0;
   lstPkBill:= TList.Create;
   //if an item is selected in lv
   if (lvBill.ItemIndex = -1) then begin exit; end
   else
   begin
        //Loop through all items and get selected item
        for i := 0 to lvBill.Items.Count - 1 do
        begin
            item := lvBill.Items.Item[i];
            if(item.Selected = true)then
            begin
                //create new item
                oPkBill := TPkBill.Create(StrToInt(lvBill.Items[i].Caption));
                //add it to a list
                lstPkBill.Add(TObject(oPkBill)); 
                //add up
                iCount := iCount +1;      
            end;
        end;
        //Now we have a list ok pkBill
        if(iCount > 1)then //other stuff I do
    end

I want to be able to free the TList and also to free the record.

Here is what I already tried:

for i := 0 to lstPkBill.Count - 1 do
begin
    //TObject(TPkBill(lstPkBill[i])).Free;  //Acces violation at adress..
    //FreeMem(TPkBill(lstPkBill[i]));   //Incompatible types
    //FreeMem(TObject(lstPkBill[i]));   //Incompatible types
end;
lstPkBill.Clear;
FreeAndNil(lstPkBill);

Thanks you for the help, it's appreciated!


Best Answer:


You have defined a record with a constructor. Calling a record constructor does not allocate memory on the heap, like a class constructor does. Your oPkBill variable exists on the stack. Calling oPkBill := TPkBill.Create(...) merely populates the members of that variable. You are then type-casting that entire variable (which only contains one Integer member) into a TObject pointer. You are not actually allocating any memory on the heap for the list item, so there is no need to free them.

I suspect what you were actually trying to do is something more like this:

type
  PPkBill = ^TPkBill;
  TPkBill = record
    PkBill: integer;
    Constructor Create(c_PkBill: integer);
  end;
constructor TPkBill.Create(c_PkBill: integer);
begin
  PkBill := c_PkBill;
end;
procedure TfrmProject.lvBillDblClick(Sender: TObject);
var   
  i: Integer;
  item: TListItem;
  oPkBill: PPkBill;
  lstPkBill: TList;
begin
  if lvBill.ItemIndex = -1 then Exit;
  //an item is selected in lv
  lstPkBill := TList.Create;
  try
    //Loop through all items and get selected items
    for i := 0 to lvBill.Items.Count - 1 do
    begin
      item := lvBill.Items.Item[i];
      if item.Selected then
      begin
        //create new item
        New(oPkBill);
        try
          oPkBill^ := TPkBill.Create(StrToInt(lvBill.Items[i].Caption));
          //add it to a list
          lstPkBill.Add(oPkBill);
        except
          Dispose(oPkBill);
          raise;
        end;
      end;
    end;
    //Now we have a list ok pkBill
    if (lstPkBill.Count > 1) then
    begin
      //other stuff I do
    end;
  finally
    for i := 0 to lstPkBill.Count - 1 do
      Dispose(PPkBill(lstPkBill[i]));
    lstPkBill.Free;
  end;
end;



Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs