Recent

Author Topic: TTabControl leaking (?)  (Read 1180 times)

chrv

  • Jr. Member
  • **
  • Posts: 58
TTabControl leaking (?)
« on: March 28, 2021, 01:00:54 pm »
Hi all,

Just testing TTabControl. I have to create and destroy tabs and associated objects at runtime.
When i free objects
Code: Pascal  [Select][+][-]
  1. for i:=TabControl1.Tabs.Count-1 downto 0 do
  2.   TabControl1.Tabs.Objects[i].Free;
  it seems tabs captions are destroyed (?) and objects are not (?).
At the end : unfreed memory blocks (1 per tab created)

When i use similar code with TListBox
Code: Pascal  [Select][+][-]
  1. for i := 0 to ListBox1.Items.Count-1 do
  2.     ListBox1.Items.Objects[i].Free;
result is as expected.
What am i missing ?

Here is my complete exemple app.
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls  ;
  9.  
  10. type
  11.   TMyObject = class(TObject)
  12.     OID : integer;
  13.   end;
  14.   { TForm1 }
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Button2: TButton;
  18.     Button3: TButton;
  19.     Button4: TButton;
  20.     Edit1: TEdit;
  21.     Label1: TLabel;
  22.     Label2: TLabel;
  23.     Label3: TLabel;
  24.     ListBox1: TListBox;
  25.     TabControl1: TTabControl;
  26.     procedure Button1Click(Sender: TObject);
  27.     procedure Button2Click(Sender: TObject);
  28.     procedure Button3Click(Sender: TObject);
  29.     procedure Button4Click(Sender: TObject);
  30.   private
  31.   public
  32.   end;
  33.  
  34. var
  35.   Form1: TForm1;
  36. implementation
  37. {$R *.lfm}
  38. { TForm1 }
  39. //Creates object and add it to ListBox
  40. procedure TForm1.Button1Click(Sender: TObject);
  41. var
  42.   aMyObject : TMyObject;
  43. begin
  44.   aMyObject := TMyObject.Create;
  45.   aMyObject.OID:=Random(20);
  46.   ListBox1.AddItem(Edit1.Text,aMyObject);
  47. end;
  48.  
  49. //Frees objects. It works OK
  50. procedure TForm1.Button2Click(Sender: TObject);
  51. var
  52.   i : integer;
  53. begin
  54.   if ListBox1.Count>0 then
  55.   for i := 0 to ListBox1.Items.Count-1 do
  56.     ListBox1.Items.Objects[i].Free;
  57.   ListBox1.Clear;
  58. end;
  59.  
  60. //Creates object and add it to TabControl
  61. procedure TForm1.Button3Click(Sender: TObject);
  62. var
  63.   aMyObject : TMyObject;
  64. begin
  65.   aMyObject := TMyObject.Create;
  66.   aMyObject.OID:=Random(20);
  67.   TabControl1.Tabs.AddObject(Edit1.Text,aMyObject);
  68.  
  69.   Edit1.Text:='';
  70. end;
  71.  
  72. //Destroys objects. Does not work as expected : memory leaks
  73. procedure TForm1.Button4Click(Sender: TObject);
  74. var
  75.   i : integer;
  76. begin
  77.   if TabControl1.Tabs.Count>0 then
  78.   //for i := 0 to TabControl1.Tabs.Count-1 do
  79.   //  TabControl1.Tabs.Objects[i].Free;          //<- crash
  80.   for i := TabControl1.Tabs.Count-1 downto 0 do
  81.     TabControl1.Tabs.Objects[i].Free;
  82.   TabControl1.Tabs.Clear;  
  83. end;
  84. end.            

Win32 Lazarus 2.0.12 FPC 3.2.0

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TTabControl leaking (?)
« Reply #1 on: March 28, 2021, 01:41:24 pm »
As a general remark, because I don't know if it is relevant here, one shouldn't use the "objects" properties of special TStrings properties (like Tabs here) because it's very posible that they are being used internally by the propety itself.

It can be easily ascertained if that is indeed the case with Tabs: add a few in design-mode and check at run-time whether Objects[] is empty or not.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

chrv

  • Jr. Member
  • **
  • Posts: 58
Re: TTabControl leaking (?)
« Reply #2 on: March 28, 2021, 09:02:29 pm »
@lucamar
@jamie
Thanks for information.

"Objects" is indeed used for another purpose
Code: Text  [Select][+][-]
  1. 44164104
  2. 44165800
  3. 44166824

What's the best workaround ?
- Not to use Tabs.Objects (of cours)
- Copy Tabs (without Objects) to a new TStrings (say "TabsNew")
- Store TMyObject to TabsNew.Objects
- Always synchronise Tabs with TabsNew

Is there a better solution ?
Win32 Lazarus 2.0.12 FPC 3.2.0

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TTabControl leaking (?)
« Reply #3 on: March 28, 2021, 09:57:20 pm »
The best, IMHO, is to keep your objects in a separate TStringList and keep it synchronized with Tabs, which basically means responding to adding/deleting a tab and a tab changing its position (e.g. when the user drags a tab to put it before/after another), if this last is allowed in your program.

So, yeah, what you outlined seems to be the best solution. Only, remember that TStrings is a quasi-abstract class and that its default implementation is TStringList, so use one of these.
« Last Edit: March 28, 2021, 10:00:36 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

chrv

  • Jr. Member
  • **
  • Posts: 58
Re: TTabControl leaking (?)
« Reply #4 on: March 28, 2021, 10:39:47 pm »
That's what i thought.

Thanks a lot

(see attachment for my implementation)
Win32 Lazarus 2.0.12 FPC 3.2.0

 

TinyPortal © 2005-2018