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:tmyobje ct;
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.
Assume I have a class
TmyObject = class(TObject)
...whatever
PmyObject = ^TmyObject;
If I have a procedure with
var myobject,myobject2:tmyobje
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
myobject2:=Tmyobject(Flist
Are they both correct ?
Thanks in Advance.
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[Inde xYouHaveHe re];
By the way do you agree that the following is buggy ? :
myobject:=Flist.items[Inde
taka a look at one of my PAQs: https://www.experts-exchange.com/questions/20517019/dynamic-array-of-TMyObject.html
ziolko.
ziolko.
myobject:=Flist.items[Inde xYouHaveHe re];
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[Inde xYouHaveHe re]);
instead
meikl ;-)
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.
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
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
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
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 ;-)
->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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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 ?
var Flist:Tlist;
Myobject1:Tmyobject;
procedure Duplicate;
var Myobject2:Tmyobject;
begin
Myobject2:=Pmyobject(Flist
Flist.add(@myobject2);
end;
begin
Flist.create;
Flist.add(Myobject.create)
Duplicate;
Myobject1:=Pmyobject(Flist
....
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
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
....
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
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
> 5. of that follows that myobject2:=PMyobject(Flist
> 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])^.InstanceSiz e));
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 ;-)
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
type
PObj = ^TObject;
var
obj : TObject;
lst : TList;
begin
lst := TList.create;
obj := TObject.create;
lst.Add(obj);
//lst.Add(@obj);
showMessage(IntToStr(PObj(
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 ;-)
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 ;-)
meikl ;-)
Me too!
Regards
J
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?
> 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.
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.
Flist.add(myobject);
then you get it in this way
myobject:=Tmyobject(Flist.
PmyObject is not needed
meikl ;-)