www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - &this pointer

reply e-t172 <idontlikespam nospam.com> writes:
Hi,

I'm a beginner with D, I've got some basis with C/C++ but I mainly 
program with PHP. Ad far as I'm concerned, D is a very interesting 
language, hence I started to develop a personal project in D to get a 
clear idea of its features ; nonetheless, during my research, I've 
noticed a behavior I considered very weird about the 'this' reference. 
According to what I understood from the documentation, it is a reference 
to the object itself, so coherently, &this should return the memory 
address of the object itself.

It that is correct, could one explain that to me (compiled with DMD 1.0) :

---

import std.stdio;
import std.string;

class Test
{
	this()
	{
		writefln("in this() itself - &this : ", &this);

		foo("called from this(), first shot");
		foo("called from this(), second shot");
	}

	void foo(char[] location)
	{
		writefln(location, " - foo() - &this : ", &this);

		bar(location);
	}

	void bar(char[] location)
	{
		writefln(location, " - bar() - &this : ", &this);
	}
}

int main()
{
	auto test = new Test();

	test.foo("called from main(), first shot");
	test.foo("called from main(), second shot");

	return 0;
}

---

$ ./test
in this() itself - &this : BFAE4394
called from this(), first shot - foo() - &this : BFAE4370
called from this(), first shot - bar() - &this : BFAE4344
called from this(), second shot - foo() - &this : BFAE4370
called from this(), second shot - bar() - &this : BFAE4344
called from main(), first shot - foo() - &this : BFAE438C
called from main(), first shot - bar() - &this : BFAE4360
called from main(), second shot - foo() - &this : BFAE438C
called from main(), second shot - bar() - &this : BFAE4360

---

In accordance with the output, the object location in memory endlessly 
changes ?! I admit to be a little startled...

e-t172
Feb 10 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
By reference it means that 'this' already *is* a pointer.
You don't need to take it's address.  If you do you're just getting the 
address of the pointer not the address of the object.

Try something like
    writefln("%x",cast(void*)this);
if you really want to see the address of the object.

--bb

e-t172 wrote:
 Hi,
 
 I'm a beginner with D, I've got some basis with C/C++ but I mainly 
 program with PHP. Ad far as I'm concerned, D is a very interesting 
 language, hence I started to develop a personal project in D to get a 
 clear idea of its features ; nonetheless, during my research, I've 
 noticed a behavior I considered very weird about the 'this' reference. 
 According to what I understood from the documentation, it is a reference 
 to the object itself, so coherently, &this should return the memory 
 address of the object itself.
 
 It that is correct, could one explain that to me (compiled with DMD 1.0) :
 
 ---
 
 import std.stdio;
 import std.string;
 
 class Test
 {
     this()
     {
         writefln("in this() itself - &this : ", &this);
 
         foo("called from this(), first shot");
         foo("called from this(), second shot");
     }
 
     void foo(char[] location)
     {
         writefln(location, " - foo() - &this : ", &this);
 
         bar(location);
     }
 
     void bar(char[] location)
     {
         writefln(location, " - bar() - &this : ", &this);
     }
 }
 
 int main()
 {
     auto test = new Test();
 
     test.foo("called from main(), first shot");
     test.foo("called from main(), second shot");
 
     return 0;
 }
 
 ---
 
 $ ./test
 in this() itself - &this : BFAE4394
 called from this(), first shot - foo() - &this : BFAE4370
 called from this(), first shot - bar() - &this : BFAE4344
 called from this(), second shot - foo() - &this : BFAE4370
 called from this(), second shot - bar() - &this : BFAE4344
 called from main(), first shot - foo() - &this : BFAE438C
 called from main(), first shot - bar() - &this : BFAE4360
 called from main(), second shot - foo() - &this : BFAE438C
 called from main(), second shot - bar() - &this : BFAE4360
 
 ---
 
 In accordance with the output, the object location in memory endlessly 
 changes ?! I admit to be a little startled...
 
 e-t172

Feb 10 2007
prev sibling next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
e-t172 wrote:
 I've 
 noticed a behavior I considered very weird about the 'this' reference. 
 According to what I understood from the documentation, it is a reference 
 to the object itself,

Correct.
 so coherently, &this should return the memory 
 address of the object itself.

Wrong. A reference in D is different from a reference in C++. If you take the address of a reference in D, you do not get the address of the object referenced, but the address of the reference itself. Think of a D reference as a pointer to the body of the class, with small differences. For one, casting between references works differently. For another, pointer arithmetic doesn't work on references. But operators like (unary) & work the same: in this case, it returns a pointer to the memory storing the address being referred to. To get the address of the object from a reference you can cast it to void*. So in your case, replace "&this" with "cast(void*)this" and you will see the same address everywhere.
Feb 10 2007
parent e-t172 <idontlikespam nospam.com> writes:
Frits van Bommel a écrit :
 A reference in D is different from a reference in C++. If you take the 
 address of a reference in D, you do not get the address of the object 
 referenced, but the address of the reference itself.
 Think of a D reference as a pointer to the body of the class, with small 
 differences. For one, casting between references works differently. For 
 another, pointer arithmetic doesn't work on references. But operators 
 like (unary) & work the same: in this case, it returns a pointer to the 
 memory storing the address being referred to.
 
 To get the address of the object from a reference you can cast it to 
 void*. So in your case, replace "&this" with "cast(void*)this" and you 
 will see the same address everywhere.

Thank you very much :) e-t172
Feb 10 2007
prev sibling next sibling parent Derek Parnell <derek psych.ward> writes:
The phrase "&this" returns the address of the hidden 'this' parameter
passed to the member functions. In other words, you are seeing the address
of a parameter on the stack. 

If you are trying to get the address of the class instance, the phrase 

   "cast(void *)this" 

seems to work, but I'm sure there are other techniques too.

-- 
Derek Parnell
Melbourne, Australia
"Justice for David Hicks!"
skype: derek.j.parnell
Feb 10 2007
prev sibling parent reply e-t172 <idontlikespam nospam.com> writes:
The following does not work :

import std.stdio;

class Test
{
	this()
	{
		void* ptr = cast(void*) this;

		(*(cast(Test*) ptr)).foo();
	}

	void foo()
	{
		writefln("OK");
	}
}

int main()
{
	auto test = new Test();

	return 0;
}

Result : segmentation fault

Could one explain why ?
Feb 11 2007
next sibling parent Brian Byrne <bdbyrne wisc.edu> writes:
e-t172 wrote:
 The following does not work :
 
 import std.stdio;
 
 class Test
 {
     this()
     {
         void* ptr = cast(void*) this;
 
         (*(cast(Test*) ptr)).foo();
     }
 
     void foo()
     {
         writefln("OK");
     }
 }
 
 int main()
 {
     auto test = new Test();
 
     return 0;
 }
 
 Result : segmentation fault
 
 Could one explain why ?

"this" is of type "Test". Therefore to recover it from a void*, do simply: (cast(Test)ptr).foo(); Brian Byrne
Feb 11 2007
prev sibling parent Derek Parnell <derek psych.ward> writes:
On Sun, 11 Feb 2007 21:14:26 +0100, e-t172 wrote:

 The following does not work :
 
 import std.stdio;
 
 class Test
 {
 	this()
 	{
 		void* ptr = cast(void*) this;
 
 		(*(cast(Test*) ptr)).foo();
 	}
 
 	void foo()
 	{
 		writefln("OK");
 	}
 }
 
 int main()
 {
 	auto test = new Test();
 
 	return 0;
 }
 
 Result : segmentation fault
 
 Could one explain why ?

You need "(cast(Test) ptr).foo();" instead. This is because 'void* ptr' contains the address of the object, and when calling object members, you need to use a /reference/ to the object and not the object itself. Casting 'ptr' to 'Test*' just tells the compiler to assume that 'ptr' points to a Test object and then using the '*' operator returns the object and not a reference to the object. If, however you had cast 'ptr' to just a 'Test', this tells the compiler to assume that 'ptr' contains a reference to the object and so it can then find the member to invoke. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Feb 11 2007