www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Pointer to Object Questions

reply %u <johnkirollos yahoo.com> writes:
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
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"%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
 John
Class 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
parent John Kiro <johnkirollos yahoo.com> writes:
== Quote from Jarrett Billingsley (kb3ctd2 yahoo.com)'s article
 "%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
 John
Class 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.
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
prev sibling parent reply BCS <nothing pathlink.com> writes:
%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
 John
 
First 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
parent reply John Kiro <johnkirollos yahoo.com> writes:
== Quote from BCS (nothing pathlink.com)'s article
 %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
 John
First 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
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? 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
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
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
next sibling parent reply John Kiro <johnkirollos yahoo.com> writes:
== Quote from Kirk McDonald (kirklin.mcdonald gmail.com)'s article

 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.)
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
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
parent reply John Kiro <johnkirollos yahoo.com> writes:
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
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
prev sibling next sibling parent "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
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
prev sibling parent reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----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
parent Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Thomas Kuehne wrote:
 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
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.org
Dec 30 2006