Recent

Author Topic: SplitString() returns TStrings?  (Read 408 times)

local-vision

  • New Member
  • *
  • Posts: 42
SplitString() returns TStrings?
« on: March 02, 2021, 02:45:04 am »
SplitString() returns TStrings not TStringList. But what is the correct way to handle this abstract class result?

Here are some test results below.

 
Code: Pascal  [Select][+][-]
  1.  
  2. unit Unit1;
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  10.   lazstringutils;
  11.  
  12. type
  13.  
  14.   { TForm1 }
  15.  
  16.   TForm1 = class(TForm)
  17.     Memo1: TMemo;
  18.     procedure FormCreate(Sender: TObject);
  19.   private
  20.     procedure SplitStringTest1;
  21.     procedure SplitStringTest2;
  22.     procedure SplitStringTest3;
  23.     procedure SplitStringTest4;
  24.   public
  25.  
  26.   end;
  27.  
  28. var
  29.   Form1: TForm1;
  30.  
  31. implementation
  32.  
  33. {$R *.lfm}
  34.  
  35. { TForm1 }
  36.  
  37. { So.. SplitString() function which returns TStrings. How to use this correctly? }
  38.  
  39. const AStringOfWords='A String Of Space Delimted Words';
  40.  
  41. var TeeStrings:TStrings;
  42.     TeeStringList:TStringList;
  43.  
  44. procedure TForm1.SplitStringTest1; //NO Memory Leak! But is this the correct way?
  45. var n:Integer;
  46. begin
  47.   try
  48.     TeeStrings:=SplitString(AStringOfWords,' ');
  49.     for n:=0 to TeeStrings.Count-1 do
  50.     begin
  51.       Memo1.Lines.Add(TeeStrings[n]);
  52.     end;
  53.   finally
  54.     TeeStrings.Free; //Freed. But I did need to Create anything?
  55.   end;
  56. end;
  57.  
  58. procedure TForm1.SplitStringTest2; //Memory Leak! But why is this not the correct way?
  59. var n:Integer;
  60. begin
  61.   try
  62.     TeeStrings:=TStrings.Create; // yep. It was created and...
  63.     TeeStrings:=SplitString(AStringOfWords,' ');
  64.     for n:=0 to TeeStrings.Count-1 do
  65.     begin
  66.       Memo1.Lines.Add(TeeStrings[n]);
  67.     end;
  68.   finally
  69.     TeeStrings.Free; //...it was freed
  70.   end;
  71.  
  72.   {Heap dump by heaptrc unit of /home/sane/Desktop/USBDriveContent/SpoonFeed/SplitString/project1
  73.   967 memory blocks allocated : 1688995/1690376
  74.   966 memory blocks freed     : 1688915/1690296
  75.   1 unfreed memory blocks : 80
  76.   True heap size : 1638400
  77.   True free heap : 1638112
  78.   Should be : 1638128
  79.   Call trace for block $00007FFFF6245C00 size 80
  80.   $00000000004642DA  FORMCREATE,  line 89 of unit1.pas
  81.   $000000000044EDF7  DOCREATE,  line 939 of include/customform.inc
  82.   $000000000044CA6D  AFTERCONSTRUCTION,  line 149 of include/customform.inc
  83.   $00000000004555E4  CREATE,  line 3184 of include/customform.inc
  84.   $000000000045F905  CREATEFORM,  line 2239 of include/application.inc
  85.   $000000000041F066  main,  line 38 of project1.lpr
  86.   $00000000004555B9  CREATE,  line 3183 of include/customform.inc
  87.   $000000000045F905  CREATEFORM,  line 2239 of include/application.inc
  88.   $000000000041F066  main,  line 38 of project1.lpr}
  89. end;
  90.  
  91. procedure TForm1.SplitStringTest3; //Memory Leak. TStringList and TStrings
  92. var n:Integer;
  93. begin
  94.   try
  95.     TeeStrings:=TStringList.Create; // Creating the TStringList
  96.     TeeStrings:=SplitString(AStringOfWords,' ');
  97.     for n:=0 to TeeStrings.Count-1 do
  98.     begin
  99.       Memo1.Lines.Add(TeeStrings[n]);
  100.     end;
  101.   finally
  102.     TeeStrings.Free;
  103.   end;
  104.  
  105.   {Heap dump by heaptrc unit of /home/sane/Desktop/USBDriveContent/SpoonFeed/SplitString/project1
  106.   967 memory blocks allocated : 1689059/1690440
  107.   966 memory blocks freed     : 1688915/1690296
  108.   1 unfreed memory blocks : 144
  109.   True heap size : 1638400
  110.   True free heap : 1638048
  111.   Should be : 1638064
  112.   Call trace for block $00007FFFF622CEC0 size 144
  113.   $00000000004642DA  FORMCREATE,  line 107 of unit1.pas
  114.   $000000000044EDF7  DOCREATE,  line 939 of include/customform.inc
  115.   $000000000044CA6D  AFTERCONSTRUCTION,  line 149 of include/customform.inc
  116.   $00000000004555E4  CREATE,  line 3184 of include/customform.inc
  117.   $000000000045F905  CREATEFORM,  line 2239 of include/application.inc
  118.   $000000000041F066  main,  line 38 of project1.lpr}
  119. end;
  120.  
  121. procedure TForm1.SplitStringTest4; //This will NOT compile as SplitString result must be of TStrings
  122. var n:Integer;
  123. begin
  124.   try
  125.     TeeStringList:=TStringList.Create;
  126.     //TeeStringList:=SplitString(AStringOfWords,' '); //will NOT compile
  127.     for n:=0 to TeeStringList.Count-1 do
  128.     begin
  129.       Memo1.Lines.Add(TeeStringList[n]);
  130.     end;
  131.   finally
  132.     TeeStringList.Free;
  133.   end;
  134. end;
  135.  
  136. procedure TForm1.FormCreate(Sender: TObject);
  137. begin
  138.   Memo1.Clear;
  139.  
  140.   SplitStringTest1;
  141.   SplitStringTest2;
  142.   SplitStringTest3;
  143.   SplitStringTest4;
  144. end;
  145.  
  146. end.
  147.  
  148.  

egsuh

  • Hero Member
  • *****
  • Posts: 683
Re: SplitString() returns TStrings?
« Reply #1 on: March 02, 2021, 03:22:57 am »
It's quite simple. SplitString() itself creates TStrings.  The definition of SplitSTring() must look like:

Code: Pascal  [Select][+][-]
  1. function SplitString(s: string): TStrings;
  2. var
  3.     arr: array of string;
  4.     ts: string;
  5. begin
  6.      if s = '' then Exit(nil); // not sure about this.  
  7.      Result:= TStrings.Create;
  8.      arr:= s.split([',']);
  9.      for ts in arr do Result.Add(ts);
  10. end;
  11.  
     

So your example2 and example3 has memory leak. The memory block assigned by TeeStrings: TStringList.Create; is not freed.

TStringList is a child class of TStrings, so TStringListVar := TStringsVar does not work.
Syntax must always be in the form of

           parent := child;

« Last Edit: March 02, 2021, 03:47:03 am by egsuh »

local-vision

  • New Member
  • *
  • Posts: 42
Re: SplitString() returns TStrings?
« Reply #2 on: March 02, 2021, 03:36:12 am »
Many thanks again for the clear and helpful info Egsuh.

Your statement:

Quote
  SplitString() itself creates TStrings

and

Quote
TStringList is a child class of TStrings 

This made everything clear to me now.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8319
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: SplitString() returns TStrings?
« Reply #3 on: March 02, 2021, 08:57:14 am »
Just FYI, there's this idiom on using functions creating volatile objects:
Code: Pascal  [Select][+][-]
  1. var
  2.   Concatenated: String;
  3.   i: Integer;
  4. ...
  5. with SplitString(AStringOfWords,' ') do
  6.   try
  7.     Concatenated := '';
  8.     for i := 0 to Count - 1 do
  9.       Concatenated := Concatenated + Strings[i];
  10.     WriteLn(Concatenated);
  11.   finally
  12.     Free;
  13.   end;
  14.  

local-vision

  • New Member
  • *
  • Posts: 42
Re: SplitString() returns TStrings?
« Reply #4 on: March 03, 2021, 05:39:26 pm »
That is something to think about. :)

 

TinyPortal © 2005-2018