Recent

Author Topic: More objects and object list questions[SOLVED]  (Read 2365 times)

jbmckim

  • Full Member
  • ***
  • Posts: 144
More objects and object list questions[SOLVED]
« on: February 23, 2018, 10:46:27 pm »
This is a companion to my previous question on oject lists.  This one however attempts to use a different approach to reading a list of objects.  It has a problem that I can't figure out.

This demo program is built from two units.  (Most of the main unit is display.)

Here's the main unit:

Code: Pascal  [Select][+][-]
  1. unit MainFormUnit;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, InsUnit, fgl;
  9.  
  10. type
  11.   TInsList = specialize TFPGObjectList<TIns>;
  12.  
  13. type
  14.  
  15.   { TForm1 }
  16.  
  17.   TForm1 = class(TForm)
  18.     ShowListButton: TButton;
  19.     ShowObjectsButton: TButton;
  20.     Memo1: TMemo;
  21.     procedure FormCreate(Sender: TObject);
  22.     procedure ShowListButtonClick(Sender: TObject);
  23.     procedure ShowObjectsButtonClick(Sender: TObject);
  24.   private
  25.  
  26.   public
  27.  
  28.   end;
  29.  
  30. const
  31.   I_NUM_ENTRIES : integer = 4;
  32.  
  33. var
  34.   Form1: TForm1;
  35.   InsList : TInsList;
  36.  
  37. implementation
  38.  
  39. {$R *.lfm}
  40.  
  41. { TForm1 }
  42.  
  43. procedure TForm1.ShowObjectsButtonClick(Sender: TObject);
  44. var
  45.   i : integer = 0;
  46.   InsObj : TIns;
  47.  
  48. begin
  49.  
  50.   InsList := TInsList.Create;
  51.  
  52.   for i := 0 to I_NUM_ENTRIES do
  53.     begin
  54.       InsObj := TIns.Create;
  55.       InsObj.Init();
  56.       InsObj.RunTimeInsNumber := i;
  57.       InsObj.InsSerial := 'testSerialNum' + IntToStr(i);
  58.       InsObj.InsName := 'Name '  + IntToStr(i);
  59.       InsList.add(InsObj);
  60.       Memo1.Lines.Add(IntToStr(InsObj.RunTimeInsNumber));
  61.       Memo1.Lines.Add(InsObj.InsSerial);
  62.       Memo1.Lines.Add(InsObj.InsName);
  63.       Memo1.Lines.Add('  ');
  64.  
  65.       InsObj.Free;
  66.     end;
  67.  
  68.   ShowListButton.Enabled:=true;
  69.  
  70. end;
  71.  
  72. procedure TForm1.ShowListButtonClick(Sender: TObject);
  73. var
  74.   i : integer = 0;
  75.   InsObj : TIns;
  76.   var p : pointer;
  77.  
  78. begin
  79.  
  80.   i := InsList.Count;
  81.  
  82.   Memo1.Lines.Add('--------------- ');
  83.   Memo1.Lines.Add('Items from list ');
  84.   Memo1.Lines.Add('--------------- ');
  85.   Memo1.Lines.Add(' ');
  86.  
  87.    for i := 0 to I_NUM_ENTRIES do
  88.      begin
  89.        InsObj := TIns.Create;
  90.        InsObj.Init();
  91.        InsObj.RunTimeInsNumber:= InsList[i].RunTimeInsNumber;
  92.        InsObj.InsSerial := InsList[i].InsSerial;
  93.        InsObj.InsName:=InsList[i].InsName;
  94.        Memo1.Lines.Add(IntToStr(InsObj.RunTimeInsNumber));
  95.        Memo1.Lines.Add(InsObj.InsSerial);
  96.        Memo1.Lines.Add(InsObj.InsName);
  97.      end;
  98.  
  99.  
  100. end;
  101.  
  102. procedure TForm1.FormCreate(Sender: TObject);
  103. begin
  104.   ShowListButton.Enabled:=false;
  105. end;
  106.  
  107. end.    

Here's the unit that contains the class from which I want to build a list:

Code: Pascal  [Select][+][-]
  1. unit InsUnit;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils;
  9.  
  10. type
  11. TIns = Class
  12.     public
  13.      RunTimeInsNumber : integer;
  14.      SortOrderInsNumber : integer;
  15.      InsName : string;
  16.      InsSerial : string;
  17.      DBFeatureStr : string;
  18.  
  19.      constructor Init();
  20.  
  21.    private const
  22.      defaultSpecLoad = 'Testing Private';
  23.  
  24.    public
  25.  
  26.      const SpecDefaults = 'test';
  27.  
  28.  end;
  29.  
  30. implementation
  31.  
  32. constructor TIns.Init();
  33. begin
  34.    RuntimeInsNumber := 0;
  35.     SortOrderInsNumber :=0;
  36.     InsName :='';
  37.     InsSerial :='';
  38.     DBFeatureStr :='';
  39.  
  40.   end;
  41.  
  42. end.

The program dies on the line  InsObj.InsSerial := InsList.InsSerial; in the section that attempts to display the values after they've been loaded to the list.  I'm guessing this is a pointer/value problem but I don't get why or how to get this demo to work.

If it would help, I can upload the entire project.  Let me know how to so/what you'd prefer if you're interested.

EDIT:  Ooops, this throws the SIGSEGV error with stack trace.

Thanks in advance.
« Last Edit: February 24, 2018, 06:16:07 pm by jbmckim »

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: More objects and object list questions
« Reply #1 on: February 23, 2018, 11:10:20 pm »
as with many objects that have index functions they are 0 based...

 What this means is  if you have X-NUMBEROF_ENTRIies, you start at 0 and end at COUNT-1

 So if a list has 10 items and you want to index them...

 For I := 0 To 9 do.....
  or
 For I := 0 To SomeList.Count-1 do...


 0 index counts as the first item..


The only true wisdom is knowing you know nothing

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: More objects and object list questions
« Reply #2 on: February 23, 2018, 11:27:56 pm »
Offending line highlighted below.


Code: Pascal  [Select][+][-]
  1. unit MainFormUnit;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, InsUnit, fgl;
  9.  
  10. type
  11.   TInsList = specialize TFPGObjectList<TIns>;
  12.  
  13. type
  14.  
  15.   { TForm1 }
  16.  
  17.   TForm1 = class(TForm)
  18.     ShowListButton: TButton;
  19.     ShowObjectsButton: TButton;
  20.     Memo1: TMemo;
  21.     procedure FormCreate(Sender: TObject);
  22.     procedure ShowListButtonClick(Sender: TObject);
  23.     procedure ShowObjectsButtonClick(Sender: TObject);
  24.   private
  25.  
  26.   public
  27.  
  28.   end;
  29.  
  30. const
  31.   I_NUM_ENTRIES : integer = 4;
  32.  
  33. var
  34.   Form1: TForm1;
  35.   InsList : TInsList;
  36.  
  37. implementation
  38.  
  39. {$R *.lfm}
  40.  
  41. { TForm1 }
  42.  
  43. procedure TForm1.ShowObjectsButtonClick(Sender: TObject);
  44. var
  45.   i : integer = 0;
  46.   InsObj : TIns;
  47.  
  48. begin
  49.  
  50.   InsList := TInsList.Create;
  51.  
  52.   for i := 0 to I_NUM_ENTRIES do
  53.     begin
  54.       InsObj := TIns.Create;
  55.       InsObj.Init();
  56.       InsObj.RunTimeInsNumber := i;
  57.       InsObj.InsSerial := 'testSerialNum' + IntToStr(i);
  58.       InsObj.InsName := 'Name '  + IntToStr(i);
  59.       InsList.add(InsObj);
  60.       Memo1.Lines.Add(IntToStr(InsObj.RunTimeInsNumber));
  61.       Memo1.Lines.Add(InsObj.InsSerial);
  62.       Memo1.Lines.Add(InsObj.InsName);
  63.       Memo1.Lines.Add('  ');
  64.  
  65.       InsObj.Free;
  66.     end;
  67.  
  68.   ShowListButton.Enabled:=true;
  69.  
  70. end;
  71.  
  72. procedure TForm1.ShowListButtonClick(Sender: TObject);
  73. var
  74.   i : integer = 0;
  75.   InsObj : TIns;
  76.   var p : pointer;
  77.  
  78. begin
  79.  
  80.   i := InsList.Count;
  81.  
  82.   Memo1.Lines.Add('--------------- ');
  83.   Memo1.Lines.Add('Items from list ');
  84.   Memo1.Lines.Add('--------------- ');
  85.   Memo1.Lines.Add(' ');
  86.  
  87.    for i := 0 to I_NUM_ENTRIES do
  88.      begin
  89.        InsObj := TIns.Create;
  90.        InsObj.Init();
  91.        InsObj.RunTimeInsNumber:= InsList[i].RunTimeInsNumber;
  92.        InsObj.InsSerial := InsList[i].InsSerial;
  93.        InsObj.InsName:=InsList[i].InsName;
  94.        Memo1.Lines.Add(IntToStr(InsObj.RunTimeInsNumber));
  95.        Memo1.Lines.Add(InsObj.InsSerial);
  96.        Memo1.Lines.Add(InsObj.InsName);
  97.      end;
  98.  
  99.  
  100. end;
  101.  
  102. procedure TForm1.FormCreate(Sender: TObject);
  103. begin
  104.   ShowListButton.Enabled:=false;
  105. end;
  106.  
  107. end.    

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: More objects and object list questions
« Reply #3 on: February 23, 2018, 11:38:17 pm »
as with many objects that have index functions they are 0 based...

 What this means is  if you have X-NUMBEROF_ENTRIies, you start at 0 and end at COUNT-1

Although i would recommend that as well, the OP is using a const (and as such is valid, assuming that all objects were created correctly and added to the list).

FWIW: OP has more issues in the code that should be addressed.

This is how it could look when using FPC:
Code: Pascal  [Select][+][-]
  1. program example;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4.  
  5. uses
  6.   Classes, SysUtils, fgl;
  7.  
  8. type
  9.   TIns = class
  10.    private
  11.     const defaultSpecLoad = 'Testing Private';
  12.    public
  13.     const SpecDefaults = 'test';
  14.    public
  15.     RunTimeInsNumber : integer;
  16.     SortOrderInsNumber : integer;
  17.     InsName : string;
  18.     InsSerial : string;
  19.     DBFeatureStr : string;
  20.    public
  21.     constructor Create;
  22.   end;
  23.  
  24.  
  25. constructor TIns.Create;
  26. begin
  27.   inherited;
  28.  
  29.   RuntimeInsNumber := 0;
  30.   SortOrderInsNumber :=0;
  31.   InsName :='';
  32.   InsSerial :='';
  33.   DBFeatureStr :='';
  34. end;
  35.  
  36.  
  37. type
  38.   TInsList = specialize TFPGObjectList<TIns>;
  39.  
  40. const
  41.   I_NUM_ENTRIES = 4;
  42.  
  43. var
  44.   InsList : TInsList;
  45.  
  46.  
  47. procedure AddObjects;
  48. var
  49.   i: integer;
  50.   InsObj : TIns;
  51. begin
  52.   for i := 0 to I_NUM_ENTRIES do
  53.   begin
  54.     InsObj := TIns.Create;
  55.     InsObj.RunTimeInsNumber := i;
  56.     InsObj.InsSerial := 'testSerialNum' + IntToStr(i);
  57.     InsObj.InsName := 'Name '  + IntToStr(i);
  58.     InsList.Add(InsObj);
  59.  
  60.     WriteLn(IntToStr(InsObj.RunTimeInsNumber));
  61.     WriteLn(InsObj.InsSerial);
  62.     WriteLn(InsObj.InsName);
  63.     WriteLn('  ');
  64.   end;
  65. end;
  66.  
  67.  
  68. procedure ShowList;
  69. var
  70.   InsObj : TIns;
  71. begin
  72.   WriteLn('--------------- ');
  73.   WriteLn('Items from list ');
  74.   WriteLn('--------------- ');
  75.   WriteLn(' ');
  76.  
  77.   for insObj in Inslist do
  78.   begin
  79.     WriteLn(IntToStr(InsObj.RunTimeInsNumber));
  80.     WriteLn(InsObj.InsSerial);
  81.     WriteLn(InsObj.InsName);
  82.   end;
  83. end;
  84.  
  85.  
  86. procedure Creation;
  87. begin
  88.   InsList := TInsList.Create;
  89. end;
  90.  
  91.  
  92. procedure Destruction;
  93. begin
  94.   InsList.Free;
  95. end;
  96.  
  97.  
  98. begin
  99.   Creation;
  100.  
  101.   AddObjects;
  102.   ShowList;
  103.  
  104.   Destruction;
  105. end.
  106.  
« Last Edit: February 24, 2018, 04:04:36 am by molly »

jbmckim

  • Full Member
  • ***
  • Posts: 144
Re: More objects and object list questions[SOLVED]
« Reply #4 on: February 24, 2018, 06:17:47 pm »
molly,

Yes.  That's it.

Any help understanding why freeing the object in this context trashes the list...or whatever the reason might be...would be appreciated.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: More objects and object list questions[SOLVED]
« Reply #5 on: February 25, 2018, 12:29:47 am »
Any help understanding why freeing the object in this context trashes the list...or whatever the reason might be...would be appreciated.
When you create the object, the address of the object in memory is stored  in your variable insobj.

When you add it to the list with InsList.Add(InsObj); then the code actually just copies the memory location of your object into the list (and not the contents of the complete object). That is called the reference to your object, which is now stored inside the list.

So, when you free up the memory which is occupated  by insobj then the reference to your object that was stored inside the list is then pointing to some dark deep corner of your memory (which can look like actual values belonging to your object/class, but now actually contains some random data).

Accessing methods or properties will then result in reading from/writing to random memory locations, which result in a sigv.
« Last Edit: February 25, 2018, 12:33:32 am by molly »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: More objects and object list questions[SOLVED]
« Reply #6 on: February 25, 2018, 01:40:27 am »
So, when you free up the memory which is occupated  by insobj then the reference to your object that was stored inside the list is then pointing to some dark deep corner of your memory (which can look like actual values belonging to your object/class, but now actually contains some random data).
The reference is still pointing to the same address but the application lost its permission to access that address due to a call to FreeMem in TObject.FreeInstance. A dangling pointer.

Accessing methods or properties will then result in reading from/writing to random memory locations, which result in a sigv.
What do you mean by "random" memory locations?

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: More objects and object list questions[SOLVED]
« Reply #7 on: February 25, 2018, 01:58:12 am »
What do you mean by "random" memory locations?
As you wrote:

Quote
The reference is still pointing to the same address ...
But, since the memory was freed it might be occupied by something else. VMT table might be screwed for instance e.g. (indirectly) pointing to random memory locations.

Quote
... but the application lost its permission to access that address due to a call to FreeMem in TObject.FreeInstance. A dangling pointer.
A dangling pointer indeed... but "the application lost its permission" ? hardly. As long as it points somewhere in heap you are allowed to read from it or write to it, as a result making an even bigger mess of things

PS: in OP's case the situation is much more predictable but it isn't always that clear.
« Last Edit: February 25, 2018, 02:01:46 am by molly »

 

TinyPortal © 2005-2018