digitalmars.D.learn - Pointer to Object Questions
- %u (90/90) Dec 30 2006 Hello Everybody
- Jarrett Billingsley (11/19) Dec 30 2006 Class variables are references to begin with. You shouldn't have to use...
- John Kiro (16/37) Dec 30 2006 expressions
- BCS (8/19) Dec 30 2006 First thing first (and this is a common gotcha) All objects are accessed...
- John Kiro (16/35) Dec 30 2006 expressions
- Kirk McDonald (19/34) Dec 30 2006 Correct. D has no member indirection operator (->) as C and C++ do. You
- John Kiro (15/29) Dec 30 2006 Speaking about casting, there is usually a need to cast a reference to a...
- Jarrett Billingsley (9/23) Dec 30 2006 Yes. Though you should use the
- John Kiro (14/14) Jan 01 2007 Thanks guys for all your comments.. I've found them invaluable in
- Jarrett Billingsley (3/13) Jan 01 2007 Right on all counts.
- Frank Benoit (keinfarbton) (32/32) Dec 30 2006 I want to add this pitfalls (3) and (5):
- Thomas Kuehne (16/18) Dec 30 2006 -----BEGIN PGP SIGNED MESSAGE-----
- Kirk McDonald (32/49) Dec 30 2006 But what you have there isn't a pointer to an object, it's a pointer to
Hello Everybody I'm trying to understand how to get pointers working in D, so I wrote this example, and still several questions are without answer. Can somebody take a look on the code below, and comment on the 3 questions in the output section? My main problem is with expressions in the form "MyClass* pObj". Thanks and Happy New Year John import std.stdio; class Point { int m_x; int m_y; static Point recentPt; static Point* pRecent; this(int x, int y) { m_x=x; m_y=y; recentPt=this; pRecent=&this; //I think incorrect //pRecent=cast(Point*)this; //I think incorrect too //pRecent=this; //compile error (cannot cast Point to Point*) } Point getMe() { return this; } Point* getPtrToMe() { return &this; } } int main() { Point p1=new Point(5,5); writefln("p1: ( %d,%d )", p1.m_x, p1.m_y); writefln("recentPt: %d",cast(void*) Point.recentPt); writefln("Point referenced by Point.recentPt: ( %d,%d )", Point.recentPt.m_x, Point.recentPt.m_y); writefln("Accessing p1 using getMe(): ( %d,%d )",p1.getMe().m_x, p1.getMe().m_y); writefln("pRecent contains: %d",cast(void*) Point.pRecent); writefln("Point referenced by Point.pRecent: ( %d,%d )", Point.pRecent.m_x, Point.pRecent.m_y); writefln("p1.getPtrToMe() returns: %d",cast(void*) p1.getPtrToMe()); writefln("Accessing p1 using getPtrToMe(): ( %d,%d )",p1.getPtrToMe().m_x, p1.getPtrToMe().m_y); Point p2=new Point(8,8); writefln("\np2: ( %d,%d )", p2.m_x, p2.m_y); writefln("recentPt: %d",cast(void*) Point.recentPt); writefln("Point referenced by Point.recentPt: ( %d,%d )", Point.recentPt.m_x, Point.recentPt.m_y); writefln("Accessing p2 using getMe(): ( %d,%d )",p2.getMe().m_x, p2.getMe().m_y); writefln("pRecent contains: %d",cast(void*) Point.pRecent); writefln("Point referenced by Point.pRecent: ( %d,%d )", Point.pRecent.m_x, Point.pRecent.m_y); writefln("p2.getPtrToMe() returns: %d",cast(void*) p2.getPtrToMe()); writefln("Accessing p2 using getPtrToMe(): ( %d,%d )",p2.getPtrToMe().m_x, p2.getPtrToMe().m_y); return 0; } p1: ( 5,5 ) recentPt: 8A0FE0 --> I guess it should be the address of p1 Point referenced by Point.recentPt: ( 5,5 ) Accessing p1 using getMe(): ( 5,5 ) pRecent contains: 12FF04 Point referenced by Point.pRecent: ( 3,4277824 ) --> what's wrong here? p1.getPtrToMe() returns: 12FE9C --> why it's not equal to pRecent (they both should be "&this"? Accessing p1 using getPtrToMe(): ( 5,5 ) --> how come it works, while using "Point.pRecent" does not? p2: ( 8,8 ) recentPt: 8A0FD0 --> OK, this shows that each point is 16-byte long ( &p1 + 16 ) Point referenced by Point.recentPt: ( 8,8 ) Accessing p2 using getMe(): ( 8,8 ) pRecent contains: 12FE6C Point referenced by Point.pRecent: ( 3,4277824 ) p2.getPtrToMe() returns: 12FE04 Accessing p2 using getPtrToMe(): ( 8,8 )
Dec 30 2006
"%u" <johnkirollos yahoo.com> wrote in message news:en5lkb$v4r$1 digitaldaemon.com...Hello Everybody I'm trying to understand how to get pointers working in D, so I wrote this example, and still several questions are without answer. Can somebody take a look on the code below, and comment on the 3 questions in the output section? My main problem is with expressions in the form "MyClass* pObj". Thanks and Happy New Year JohnClass variables are references to begin with. You shouldn't have to use Class* types except under odd circumstances. When you initialize pRecent, you are giving it the address of a variable on the stack (the "this" pointer is just a parameter to the class method). So when you access it later, it gives garbage. Same thing with getPtrToMe -- since the 'this' pointer will probably end up at a different location on the stack, it won't give the same address as pRecent. Accessing through getPtrToMe is working, but probably only through sheer luck of the 'this' variable on the stack not being clobbered.
Dec 30 2006
== Quote from Jarrett Billingsley (kb3ctd2 yahoo.com)'s article"%u" <johnkirollos yahoo.com> wrote in message news:en5lkb$v4r$1 digitaldaemon.com...wroteHello Everybody I'm trying to understand how to get pointers working in D, so Iexpressionsthis example, and still several questions are without answer. Can somebody take a look on the code below, and comment on the 3 questions in the output section? My main problem is withto usein the form "MyClass* pObj". Thanks and Happy New Year JohnClass variables are references to begin with. You shouldn't haveClass* types except under odd circumstances. When you initialize pRecent, you are giving it the address of avariable onthe stack (the "this" pointer is just a parameter to the classmethod). Sowhen you access it later, it gives garbage. Same thing withgetPtrToMe --since the 'this' pointer will probably end up at a differentlocation on thestack, it won't give the same address as pRecent. Accessing through getPtrToMe is working, but probably only through sheer luck of the'this'variable on the stack not being clobbered.So, as BCS said, "&this" is the address of the reference to the object (I have a comment on this, and I'll post it in a separate reply), and the reference is passed to the member function on the stack. So in conclusion, I was using the address of a temp stack variable. Thanks for your useful comment John
Dec 30 2006
%u wrote:Hello Everybody I'm trying to understand how to get pointers working in D, so I wrote this example, and still several questions are without answer. Can somebody take a look on the code below, and comment on the 3 questions in the output section? My main problem is with expressions in the form "MyClass* pObj". Thanks and Happy New Year JohnFirst thing first (and this is a common gotcha) All objects are accessed by reference. class Foo{} Foo* f; // this is a pointer to a reference (pointer) to an object Foo g; // this is a reference to an object regular types are not int* p; //pointer to int
Dec 30 2006
== Quote from BCS (nothing pathlink.com)'s article%u wrote:wroteHello Everybody I'm trying to understand how to get pointers working in D, so Iexpressionsthis example, and still several questions are without answer. Can somebody take a look on the code below, and comment on the 3 questions in the output section? My main problem is withaccessedin the form "MyClass* pObj". Thanks and Happy New Year JohnFirst thing first (and this is a common gotcha) All objects areby reference. class Foo{} Foo* f; // this is a pointer to a reference (pointer) to an object Foo g; // this is a reference to an object regular types are not int* p; //pointer to intOK, but why does the compiler accepts something like: Point* pp1 = &p1; writefln("Accessing p1 using pp1: ( %d,%d )", pp1.m_x, pp1.m_y); I mean it seems that the leftside of "." can be either an object reference (p1) or a pointer to an object reference (pp1). Is this indeed the case? BTW, I tested the above 2 statements in main(), and the result was correct. Anyway, I guess I have to give up using pointers to objects. (may be it's OK in structs, not classes??) Regards John
Dec 30 2006
John Kiro wrote:OK, but why does the compiler accepts something like: Point* pp1 = &p1; writefln("Accessing p1 using pp1: ( %d,%d )", pp1.m_x, pp1.m_y); I mean it seems that the leftside of "." can be either an object reference (p1) or a pointer to an object reference (pp1). Is this indeed the case?Correct. D has no member indirection operator (->) as C and C++ do. You just use . for everything. (The compiler knows if you're talking about a pointer or not, and is smart enough to figure it out.)BTW, I tested the above 2 statements in main(), and the result was correct. Anyway, I guess I have to give up using pointers to objects. (may be it's OK in structs, not classes??)Since classes are by reference, anyway, there's no good reason to throw around pointers to objects. If you /really/ want a pointer to a class instance, you can cast the reference to a void*: Foo f = new Foo; void* ptr = cast(void*)f; (This should reinforce the fact that class references are just pointers.) However, this is pretty darned hackish, and usually serves little purpose. (Once cast to void*, you can't use that void* to access members of the class without casting it back.) The only use I can think of for this is when keeping references to GC-controlled objects. -- Kirk McDonald Pyd: Wrapping Python with D http://pyd.dsource.org
Dec 30 2006
== Quote from Kirk McDonald (kirklin.mcdonald gmail.com)'s articleCorrect. D has no member indirection operator (->) as C and C++ do. You just use . for everything. (The compiler knows if you're talking about a pointer or not, and is smart enough to figure it out.)hmmm.. thanks for clarifying this point.Since classes are by reference, anyway, there's no good reason to throw around pointers to objects. If you /really/ want a pointer to a class instance, you can cast the reference to a void*: Foo f = new Foo; void* ptr = cast(void*)f; (This should reinforce the fact that class references are just pointers.) However, this is pretty darned hackish, and usually serves little purpose. (Once cast to void*, you can't use that void* to access members of the class without casting it back.) The only use I can think of for this is when keeping references to GC-controlled objects.Speaking about casting, there is usually a need to cast a reference to an integer & vice-versa; I'm specifically pointing to the case of using a function like the Win32 API function SetWindowLong(), in order to link a window with a corresponding object. Here is how I did it: //Linking view window to view obj: SetWindowLong(hwndView,0,cast(uint)(cast(CView*)this)); //retrieve the object given the window handle: cast(CView)cast(CView*)GetWindowLong(hwndView,0); Casting to void* instead of CView* also compiled without errors. So is this the usual way of doing such thing? I mean double casting? Because casting an object to int or vice-versa is rejected by the compiler. Regards John
Dec 30 2006
"John Kiro" <johnkirollos yahoo.com> wrote in message news:en6pvm$23fk$1 digitaldaemon.com...Speaking about casting, there is usually a need to cast a reference to an integer & vice-versa; I'm specifically pointing to the case of using a function like the Win32 API function SetWindowLong(), in order to link a window with a corresponding object. Here is how I did it: //Linking view window to view obj: SetWindowLong(hwndView,0,cast(uint)(cast(CView*)this)); //retrieve the object given the window handle: cast(CView)cast(CView*)GetWindowLong(hwndView,0); Casting to void* instead of CView* also compiled without errors. So is this the usual way of doing such thing? I mean double casting? Because casting an object to int or vice-versa is rejected by the compiler.Yes. Though you should use the cast(uint)cast(void*)this form, as this is the more generally accepted way. It makes it obvious that you're getting the pointer value of the reference, compared to cast(uint)cast(CView*)this Since 'this' is of type CView, casting CView to CView* doesn't really make sense, but casting to void* does -- it says "I want a raw pointer."
Dec 30 2006
Thanks guys for all your comments.. I've found them invaluable in this tricky part of my D language exploration :-) As a summary: - CObj obj2=obj1; obj2 is a reference to obj1 (both obj1 & obj2 refer to the same object). So no new object is created. - CObj* pRefObj1=&obj1; pRefObj1 is the address of the reference of the object, not a pointer to the object itself.. TAKE CARE! - void* pObj1=cast(void*)obj1; pObj1 is a pointer to the object itself (as object pointers in C++) Happy New Year John
Jan 01 2007
"John Kiro" <johnkirollos yahoo.com> wrote in message news:enavsd$49l$1 digitaldaemon.com...As a summary: - CObj obj2=obj1; obj2 is a reference to obj1 (both obj1 & obj2 refer to the same object). So no new object is created. - CObj* pRefObj1=&obj1; pRefObj1 is the address of the reference of the object, not a pointer to the object itself.. TAKE CARE! - void* pObj1=cast(void*)obj1; pObj1 is a pointer to the object itself (as object pointers in C++)Right on all counts.
Jan 01 2007
I want to add this pitfalls (3) and (5): interface I {} class O : I {} void main(){ O o = new O; O[] oa; I[] ia; // (1) I i1 = o; // downcast: This is ok. // The compiler does apply a pointer adjustement. // (2) O o2 = cast(O)i1; // upcast: Needs explicit cast. This is ok. // The compiler does apply a pointer adjustement. // (3) void* ptr = cast(void*)o; I i2 = cast(I)ptr; // error! // The compiler cannot apply the pointer adjustement. // will result in undefined behaviour. // (4) ia.length = oa.length; for( int idx = 0; idx < oa.length; idx++ ){ ia[idx] = oa[idx]; } // and array cannot be casted in one step. // this can be done with a templated "arraycast" // (5) ia = cast(I[])oa; // error, this is something like (3). "reinterpret_cast" // again undevined behaviour }
Dec 30 2006
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Kirk McDonald schrieb am 2006-12-30: <snip>Since classes are by reference, anyway, there's no good reason to throw around pointers to objects.There is at least one valid use case for pointers to objects: Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFFlv+lLK5blCcjpWoRArMqAJwK3ylM4s/2PGsiHp38n1dKUIAKIgCcCig3 CU554YE1xrzlEAb1bycOqFM= =vTmJ -----END PGP SIGNATURE-----
Dec 30 2006
Thomas Kuehne wrote:Kirk McDonald schrieb am 2006-12-30: <snip>But what you have there isn't a pointer to an object, it's a pointer to a reference. This is an important distinction. import std.stdio; class Foo{} void main() { Foo f = new Foo; void* ptr = cast(void*)f; Foo* fptr = &f; writefln("ptr: %s", ptr); writefln("fptr: %s", fptr); writefln("*fptr: %s", *cast(void**)fptr); } $ ./test ptr: B7CBAFE0 fptr: BF96E110 *fptr: B7CBAFE0 In this example, ptr is a pointer to the actual object. fptr is a pointer to the /reference/. Because variables of type 'Foo' are actually pointers, variables of type Foo* are pointers to pointers. The following, therefore, is a very bad idea: Foo* func() { Foo f = new Foo; return &f; } This returns a pointer to a stack variable (the Foo reference f). This is a bad idea for the same reason returning a pointer to any stack variable is a bad idea. -- Kirk McDonald Pyd: Wrapping Python with D http://pyd.dsource.orgSince classes are by reference, anyway, there's no good reason to throw around pointers to objects.There is at least one valid use case for pointers to objects: Thomas
Dec 30 2006