Recent

Author Topic: Problem with TFPGObjectList  (Read 14786 times)

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Problem with TFPGObjectList
« on: July 28, 2016, 11:44:20 am »
I am trying to use TFPGObjectList but I get a SIGSEGV error which occurs when at the line
 A.Add(B);
and I cant see why.

The program just adds a single object ('Lazarus',28,7)  to an empty list.

Any ideas gratefully received.

Code: Pascal  [Select][+][-]
  1. program project1;
  2. uses
  3.   sysutils, fgl;
  4.  
  5. type
  6.     TItem = class
  7.       s:string;
  8.       p:integer;
  9.       q:integer;
  10.       procedure SetItem(f1:string;f2:integer;f3:integer);
  11.     end;
  12.  
  13.     TObjectList = specialize TFPGObjectList<TItem>;
  14.  
  15.     procedure TItem.SetItem(f1:string;f2:integer;f3:integer);
  16.     begin
  17.        s:=f1;
  18.        p:=f2;
  19.        q:=f3;
  20.     end;
  21.  
  22.  
  23. var
  24.   A:TObjectList;
  25.   B:TItem;
  26.  
  27. procedure ShowObjectList(Z:TObjectList);
  28. var
  29.   k:integer;
  30. begin
  31.    For k:= 0 to Z.count-1 do
  32.    begin
  33.       writeln(k:4,  Z[k].s:6,   Z[k].p:4, Z[k].q:4);
  34.    end;
  35.    writeln;
  36. end;
  37.  
  38.  
  39. begin
  40.   writeln('TFPGObjectList');
  41.  
  42.   A:=TObjectList.create;
  43.  
  44.   B:=TItem.create;
  45.   B.SetItem('Lazarus',28,7);
  46.  
  47.   A.Add(B);
  48.  
  49.   ShowObjectList(A);
  50.   writeln(A.Count);
  51.  
  52.   B.free;
  53.   A.free;
  54.  
  55.   writeln('---done----');
  56.   readln;
  57. end.
  58.  


Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Problem with TFPGObjectList
« Reply #1 on: July 28, 2016, 12:06:43 pm »
Either remove the
  B.Free;
or
after its creation set
  A.FreeObjects:=False;

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Problem with TFPGObjectList
« Reply #2 on: July 28, 2016, 12:49:20 pm »
Either remove the
  B.Free;
or
after its creation set
  A.FreeObjects:=False;
Or call Create with parameter false.

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Problem with TFPGObjectList
« Reply #3 on: July 28, 2016, 12:54:46 pm »
@Leledumbo:
Indeed, that is the better solution, because the programmer can express intend over default behavior that may not be known to him. As is the case here.
Specialize a type, not a var.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: Problem with TFPGObjectList
« Reply #4 on: July 28, 2016, 01:07:51 pm »
Both
   A.FreeObjects:=False;
and
     A:=TObjectList.create(free);
prevent the SIGSEG. 

However if I try to add a second item then the second overwrites the first in the list. For instance in the code below

Code: Pascal  [Select][+][-]
  1.   A.FreeObjects:=False;
  2.  
  3.   B.SetItem('Lazarus',28,7);
  4.   A.Add(B);
  5.   ShowObjectList(A);
  6.   writeln(A.Count);
  7.  
  8.  
  9.   B.SetItem('Free Pascal',15,9);
  10.   A.Add(B);
  11.  
  12.   ShowObjectList(A);
  13.   writeln(A.Count);
  14.  

the output is

Code: Pascal  [Select][+][-]
  1. TFPGObjectList
  2.    0Lazarus  28   7
  3.  
  4. 1
  5.    0Free Pascal  15   9
  6.    1Free Pascal  15   9
  7.  
  8. 2
  9. ---done----
  10.  

How might I prevent this?

Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

Blaazen

  • Hero Member
  • *****
  • Posts: 3237
  • POKE 54296,15
    • Eye-Candy Controls
Re: Problem with TFPGObjectList
« Reply #5 on: July 28, 2016, 01:30:20 pm »
Because you didn't create a new object. You are operating (SetItem) with the same item and you inserted it twice to the list (i.e. objectlist contains two references to the same object).
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: Problem with TFPGObjectList
« Reply #6 on: July 28, 2016, 02:40:05 pm »
@Blaazen Thanks

What is the best way of creating a List of 1000 objects using TFPGObjectList? Do I have to create an array of them first?

(With TFPGList you add the items in turn to the list as I have here, but that obviously doesn't work with TFPGObjectList).
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

sfeinst

  • Full Member
  • ***
  • Posts: 230
Re: Problem with TFPGObjectList
« Reply #7 on: July 28, 2016, 03:30:19 pm »
If you are hardcoding everything, just use a For loop.  Inside the for loop use
B := TItem.Create;
B.SetItem(..whatever data you want..);
A.Add(B);

The problem you are having is you only create once.  You have to create every time.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: Problem with TFPGObjectList
« Reply #8 on: July 29, 2016, 12:48:09 am »
Thanks

I can now create a list. I am trying to search it with

Code: Pascal  [Select][+][-]
  1.   B:=TItem.create;
  2.   B.SetItem('Lazarus',3,7);
  3.   writeln(A.IndexOf(B));

The result is -1 which means (Lazarus 3,7) can't be found, whereas the answer should be 1 (It ends up in the second position)..

To check I added
Code: Pascal  [Select][+][-]
  1.   If B=A.Items[1] then
  2.      writeln('Equal')
  3.   else
  4.       writeln('Not equal');

and got the answer 'Not equal'

Any ideas?

Full code
Code: Pascal  [Select][+][-]
  1. program project1;
  2. uses
  3.   sysutils, fgl;
  4.  
  5. type
  6.     TItem = class
  7.       s:string;
  8.       p:integer;
  9.       q:integer;
  10.       procedure SetItem(f1:string;f2:integer;f3:integer);
  11.       procedure ShowItem;
  12.     end;
  13.  
  14.     TObjectList = specialize TFPGObjectList<TItem>;
  15.  
  16.     procedure TItem.SetItem(f1:string;f2:integer;f3:integer);
  17.     begin
  18.        s:=f1;
  19.        p:=f2;
  20.        q:=f3;
  21.     end;
  22.  
  23.     procedure TItem.ShowItem;
  24.     begin
  25.        writeln(s:12,   p:4,  q:4);
  26.     end;
  27.  
  28.  
  29. var
  30.   A:TObjectList;
  31.   B:TItem;
  32.  
  33. procedure ShowTitle(Message:string);
  34. begin
  35.      writeln;
  36.      writeln(Message);
  37.      writeln('---------------');
  38. end;
  39.  
  40. procedure ShowObjectList(Z:TObjectList);
  41. var
  42.   k:integer;
  43. begin
  44.    For k:= 0 to Z.count-1 do
  45.    begin
  46.       writeln(k:4,  Z[k].s:12,   Z[k].p:4, Z[k].q:4);
  47.    end;
  48.    writeln;
  49. end;
  50.  
  51. function compare1(const a, b: TItem): Integer;
  52. begin
  53.   If a.s > b.s then
  54.      Result := 1;
  55.   If a.s = b.s then
  56.      Result := 0;
  57.   If a.s < b.s then
  58.      Result := -1;
  59. end;
  60.  
  61. function compare2(const a, b: TItem): Integer;
  62. begin
  63.   Result := a.p - b.p;
  64. end;
  65.  
  66. function compare3(const a, b: TItem): Integer;
  67. begin
  68.   Result := a.q - b.q;
  69. end;
  70.  
  71.  
  72. begin
  73.   ShowTitle('TFPGObjectList');
  74.  
  75.   A:=TObjectList.create;
  76.   A.FreeObjects:=False;
  77.  
  78.   ShowTitle('Adding objects');
  79.  
  80.   B:=TItem.create;
  81.   B.SetItem('Lazarus',3,7);
  82.   A.Add(B);
  83.  
  84.   B:=TItem.create;
  85.   B.SetItem('Python',8,5);
  86.   A.Add(B);
  87.  
  88.   B:=TItem.create;
  89.   B.SetItem('Free Pascal',3,10);
  90.   A.Add(B);
  91.  
  92.   B:=TItem.create;
  93.   B.SetItem('Visual Basic',5,11);
  94.   A.Add(B);
  95.   writeln('Index of B is ',A.IndexOf(B));
  96.  
  97.   ShowTitle('Sort by column 1');
  98.   A.Sort(@Compare1);
  99.   ShowObjectList(A);
  100.   writeln(A.Count);
  101.  
  102.   ShowTitle('Sort by column 2');
  103.   A.Sort(@Compare2);
  104.   ShowObjectList(A);
  105.   writeln(A.Count);
  106.  
  107.   ShowTitle('Sort by column 3');
  108.   A.Sort(@Compare3);
  109.   ShowObjectList(A);
  110.   writeln(A.Count);
  111.  
  112.   B:=TItem.create;
  113.   B.SetItem('Lazarus',3,7);
  114.   writeln(A.IndexOf(B));
  115.  
  116.   If B=A.Items[1] then
  117.      writeln('Equal')
  118.   else
  119.       writeln('Not equal');
  120.  
  121.   B.free;
  122.   A.free;
  123.  
  124.   writeln('---done----');
  125.   readln;
  126. end.
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Problem with TFPGObjectList
« Reply #9 on: July 29, 2016, 01:00:17 am »
Any ideas?
They are two separate objects as you created two of them (containing the same field values, i give you that) , as such they are not the same. Hence the answer of -1 (or not equal) you got.

HappyLarry

  • Full Member
  • ***
  • Posts: 155
Re: Problem with TFPGObjectList
« Reply #10 on: July 29, 2016, 01:04:58 am »
Fair point, but how can you create a TItem object in order to search the list using A.IndexOf(T:TItem) otherwise?
Use Lazarus and Free Pascal and stand on the shoulders of giants . . . very generous giants. Thank you.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Problem with TFPGObjectList
« Reply #11 on: July 29, 2016, 01:56:41 am »
..., but how can you create a TItem object in order to search the list using A.IndexOf(T:TItem) otherwise?
You can't, period.

Each item (=object/class) that you create is an individual item, that has no association with all the other items that you have stored in the list (or any other class item that you have created outside that list).

The way to use (a specialized) TObjectList is by creating those individual items, store them and parse the list in order to 'find' an item. In case you'd like to use indexOf you would store the pointer to that particular item into a variable so that you can use that later on.

I think that what you're actually looking for is a so-called associative list, e.g. a list which can store items for you but that are associated with a (unique) number or string.

For simple cases you can use TStringList for that, as it is also capable of storing objects. But, since you are already trying to solve things with generics, you would be actually looking for a so called dictionary list. In such a list you can store items and associate each item stored with a string or other value.

But, i believe fpc has no dictionary class of it's own ? You might be able to find something here  or perhaps some-one around here as a link to a generics collection that might be able to help you out.

If a dictionary is not what you seek then the only other option that could perhaps be viable is to adjust the objectlist to your likings , by for example overriding the indexof method or by adding helpers that allow you to search the list as you would like (on field names).

edit:
PS: found a thread here with a link to here.
« Last Edit: July 29, 2016, 02:42:05 am by molly »

shobits1

  • Sr. Member
  • ****
  • Posts: 271
  • .
Re: Problem with TFPGObjectList
« Reply #12 on: July 29, 2016, 05:37:48 am »
or you could create a function that return the index of item,, something like this :

Code: Pascal  [Select][+][-]
  1. function GetItemIndex(AList: TObjectList; AstrS: string; AintP, AintQ : Integer): Integer;
  2. var
  3.   i: Integer;
  4.   item: TItem;
  5. begin
  6.   result := -1;
  7.   for i := 0 to Pred(AList.Count) do
  8.   begin
  9.      item := AList[i];
  10.      if (item.p <> AintP) or (item.q <> AintQ) then
  11.         Continue;
  12.  
  13.      // use CompareStr if you want case sensitivity
  14.      if CompareText(item.s, AstrS)=0 then
  15.         Exit(i);
  16.   end;
  17. end;
  18.  
  19. // if you wish to pass TItem directly.
  20. function GetItemIndex(AList: TObjectList; AItem: TItem): Integer;
  21. begin
  22.    Result := GetItemIndex( AList, AItem.s, AItem.p, AItem.q);
  23. end;

bear in mind that this is not the most effective way but it works  ;).
« Last Edit: July 29, 2016, 05:39:42 am by shobits1 »

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: Problem with TFPGObjectList
« Reply #13 on: July 29, 2016, 07:50:48 am »
But, i believe fpc has no dictionary class of it's own ?
In the FGL there is for example TFPGMap<TKey,TData> which has dictionary semantics. It even has a map for reference counted objects:TFPGMapInterfacedObjectData. And it has fast search capabilities.
There is also THashMap in FCL-STL, which has also TDictionary semantics. Both are a TDictionary implementation in all but name.
So if you want a dictionary (which is the same as a map) you can do:
Code: Pascal  [Select][+][-]
  1. uses fgl;
  2. type
  3.   TDictionary<TKey,TValue>  = class(TFPGMap<TKey,TValue>);
  4. // or alternatively
  5. uses ghashmap;
  6. type
  7.   TDictionary<TKey,TValue> = class(THashMap<TKey,TValue>);
  8. // or alternatively non-generic simply:
  9. uses contnrs;
  10.  TDictionary = class(TFPObjectHashTable);
  11.  

Hey! Presto! TDictionary ;)

Because a map = dictionary = table!  in the context of data structure theory. Mathematically map is the correct name, btw.
The first is faster with inserts, the second is faster with searches.

There's also the sparta generics library of course that I prefer, but is not (yet?) in the distribution.
« Last Edit: July 29, 2016, 08:57:52 am by Thaddy »
Specialize a type, not a var.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Problem with TFPGObjectList
« Reply #14 on: July 29, 2016, 09:19:46 am »
Thanks Thaddy,

I read your intial post which got me searching on the: why on earth i missed that. Seems i shamefully overlooked the maps  :-[

The edited post is even nicer. Thank you for that.  8-)

Now, let's see what OP has in mind while i go toying with what you posted.

 

TinyPortal © 2005-2018