Jump to page: 1 2
Thread overview
Pointer to Object Questions
Dec 30, 2006
%u
Dec 30, 2006
John Kiro
Dec 30, 2006
BCS
Dec 30, 2006
John Kiro
Dec 30, 2006
Kirk McDonald
Dec 30, 2006
John Kiro
Jan 01, 2007
John Kiro
Dec 30, 2006
Thomas Kuehne
Dec 31, 2006
Kirk McDonald
December 30, 2006
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


########################### code ########################### 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;
}

########################### Output ###########################

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 )

December 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
> 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.


December 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
> 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
December 30, 2006
== 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
December 30, 2006
== 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

December 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
December 30, 2006
== 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
December 30, 2006
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

}

December 30, 2006
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:

#
# ClassType[IndexType] aa;
# //...
# ClassType* c = index in aa;
#

Thomas


December 31, 2006
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:
> 
> #
> # ClassType[IndexType] aa;
> # //...
> # ClassType* c = index in aa;
> #
> 
> 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
« First   ‹ Prev
1 2