Link to home
Start Free TrialLog in
Avatar of Soko
Soko

asked on

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.





Avatar of kretzschmar
kretzschmar
Flag of Germany image

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 ;-)
Avatar of Soko
Soko

ASKER

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];
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 ;-)
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
Avatar of Soko

ASKER

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
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 ;-)





ASKER CERTIFIED SOLUTION
Avatar of sfock
sfock

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Soko

ASKER

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 ?
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
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
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 ;-)
Avatar of Soko

ASKER

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 ?
i agree to give the points to sfock for best explaination

meikl ;-)
Me too!

Regards
J
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?
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.