• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 238
  • Last Modified:

getting an object pointed by an item within a Tlist in delphi6

It is easy to create bug with pointer so I would like to check the following (I know Tobjectlist  is more handy but I try to findout a bug in a code written with TLIST) :

Assume I have a class
TmyObject = class(TObject)
...whatever

PmyObject = ^TmyObject;

If I have a procedure with
var myobject,myobject2:tmyobject;
Flist:Tlist;
begin
Flist:=Tlist.create;
myobject:=Tmyobject.create;
Flist.add(myobject)// suspicious line 1
.....
end;

Is the suspicious line above correct or could it cause a bug ? As Myobject is essentially a pointer It should be ok and it is accepted by the compiler but there might be something wrong with this coding.

Some more : assume I want to access to the object pointed by Flist.items[0] consider the two following possibilities :

myobject2:=PMyobject(Flist.items[0])^;
myobject2:=Tmyobject(Flist.items[0]);

Are they both correct ?

Thanks in Advance.





0
Soko
Asked:
Soko
  • 4
  • 4
  • 4
  • +2
1 Solution
 
kretzschmarCommented:
if you add it in this way

Flist.add(myobject);

then you get it in this way

myobject:=Tmyobject(Flist.items[IndexYouHaveHere]);

PmyObject is not needed

meikl ;-)
0
 
SokoAuthor Commented:
OK That was my feeling too but I wanted to check. I will wait a little if you don't mind and If I don't get any other comment telling me that something could be buggy there I will give the points (-:

By the way do you agree that the following is buggy ? :
myobject:=Flist.items[IndexYouHaveHere];
0
 
ziolkoCommented:
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
kretzschmarCommented:
myobject:=Flist.items[IndexYouHaveHere];

you need a typecast here,
because pointer and tobject are not of same type,
even a tobject is a pointer (the compiler may not compile)

use
myobject:=Tmyobject(Flist.items[IndexYouHaveHere]);
instead

meikl ;-)
0
 
j42Commented:
Hi,

Just to chip in my lot:
From a TList you will get what you throw in:

A)
myList.Add(TMyObj.Create);
...
myObj := TMyObj(myList.Items[i]);

B)
myList.Add(@TMyObj.Create)
...
myObj := PMyObj(myList.Items[i])^;



Regards
0
 
SokoAuthor Commented:
J42 Your answer ring a bell :Tlist is a pointer list so what is the exact difference between myList.Add(TMyObj.Create and myList.Add(@TMyObj.Create) ?
myList.Items[i] is a pointer in both case .

May be in case A myList.Items[i] point to the object and in case B myList.Items[i] point to a pointer which point to the object ? I'm not sure
0
 
kretzschmarCommented:
with @.. you store the adress of the pointer to the object

->pointer^.object

without you have a object

->object

keep in mind the tobject is already a pointer,
but strongly typed, whereas a pointer is "typeless",
thats why you need a typecast


btw
if stored in this way
myList.Add(@TMyObj.Create)

this
myObj := PMyObj(myList.Items[i])^;

is the same as this
myObj := TMyObj(myList.Items[i]^);

you see, also here is PMyObj not really needed

meikl ;-)





0
 
sfockCommented:
just trying to make it a bit more clear:

1. the content of a variable of the type TAnyObject is a Reference
2. A Reference is _not_ a pointer (even if it is pretty similar in sense)
3. the operator @ returns the pointer of the variable passed after the operater so that : @myObject returns the address of the reference of the instance of TMyObject
4. the type of an object reference and a pointer are both 32bit long values wich makes it possible to cast them to each other for storing reasons.
5. of that follows that myobject2:=PMyobject(Flist.items[0])^;
is a bug because you treat the reference as a pointer and try to deref it and assign this to a ObjectReference variable
If you'd add(@myObject); it would be okay

i hope that helps to clear the thing up
0
 
SokoAuthor Commented:
I See so thank you sfock for this explanations and also thank you  kretzschmar. Now If I have understood things well the following should be bug (not  obvious at first glance)

var Flist:Tlist;
Myobject1:Tmyobject;

procedure Duplicate;
var Myobject2:Tmyobject;
begin
Myobject2:=Pmyobject(Flist.items[0])^;
Flist.add(@myobject2);
end;

begin
Flist.create;
Flist.add(Myobject.create);
Duplicate;
Myobject1:=Pmyobject(Flist.items[1])^;
....
end;

I think it is a bug because once the procedure Duplicate end, myobject2 reference disappear and therefore Flist.items[1]) is pointing to an irrelevant address. Am I correct here ?
0
 
sfockCommented:
yes right.

To correct the code do the following:

var Flist:Tlist;
Myobject1:Tmyobject;

procedure Duplicate;
begin
Flist.add(Flist.items[0]);
end;

begin
Flist.create;
Flist.add(Myobject.create);
Duplicate;
Myobject1:=Tmyobject(Flist.items[1]);
....
end;

Just try to imagine it like this : TList stores pointers, pointers are 32-BitValues. Object references are 32-bit values too so you can Hard cast them without changing the representation. if you call "Flist.add(Myobject.create);" delphi makes an implicit cast for you. when you retrieve the 32-bit value back you have to cast it back to the type it actually is.
But dont forget, you do not duplicate a object instance here you are only duplicating a object reference
0
 
j42Commented:
Hi sfock,

> 5. of that follows that myobject2:=PMyobject(Flist.items[0])^;
> is a bug

Will you really call it a bug? I suppose it will compile and run. Maybe it is bad style unless you have a good reason to do it that way...

Best of luck
J
0
 
sfockCommented:
Hi j42

well yes it will compile but not run, if you have added the object with list.add(myObject);.
In this sense i was unprecise because if you add list.add(@myObject); will work fine, unless the "myObject" variable ist still valid when trying to get it.

you might veryfy that

procedure TForm1.Button1Click(Sender: TObject);
type
  PObj = ^TObject;
var
  obj : TObject;
  lst : TList;
begin
  lst := TList.create;
  obj := TObject.create;
  lst.Add(obj);
  //lst.Add(@obj);
  showMessage(IntToStr(PObj( lst.Items[0])^.InstanceSize));
  obj.free;
  lst.free;
end;

will cause an AV. If you comment lst.Add(@obj); in and lst.Add(obj); out it will of corse run, but don't try the same over the edge of the current stack frame ;-)
0
 
SokoAuthor Commented:
Ok sfock Thank you very much.Things are clear now. Both  kretzschmar, j42 and yourself have been very helpfull but I Think that your answer was more complete and make me understand what is correct and what is not and also the reason behind it. So I Think I should give the points to you if kretzschmar and j42 don't mind ?
0
 
kretzschmarCommented:
i agree to give the points to sfock for best explaination

meikl ;-)
0
 
j42Commented:
Me too!

Regards
J
0
 
j42Commented:
kretzschmar,

> myObj := TMyObj(myList.Items[i]^);
I know this will work but I do not know why! It takes the content of a typeless pointer. What is that? Compiler magic?
0
 
sfockCommented:
thanks for the flowers guys ;-)

j42
myObj := TMyObj(myList.Items[i]^);
is no compiler magic and it works if you added the following way:
myList.Add(@myObject);

so remember the add command add's a pointer to a reference

myList.Items[i] returns the pointer with dereferencing it you get the reference itself where windows finds the referenece and with the hard cast TMyObj() you simply take any doubt from the compiler that you really want to treat the next 4 bytes at this memory position as a Object reference of the type TMyObj and assign it to the local variable.

0

Featured Post

Become an Android App Developer

Ready to kick start your career in 2018? Learn how to build an Android app in January’s Course of the Month and open the door to new opportunities.

  • 4
  • 4
  • 4
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now