Is the “this” pointer just a compile time thing?
up vote
25
down vote
favorite
I asked myself whether the this
pointer could be overused since I usually use it every single time I refer to a member variable or function. I wondered if it could have performance impact since there must be a pointer which needs to be dereferenced every time. So I wrote some test code
struct A {
int x;
A(int X) {
x = X; /* And a second time with this->x = X; */
}
};
int main() {
A a(8);
return 0;
}
and surprisingly even with -O0
they output the exact same assembler code.
Also if I use a member function and call it in another member function it shows the same behavior. So is the this
pointer just a compile time thing and not an actual pointer? Or are there cases where this
is actually translated and dereferenced? I use GCC 4.4.3 btw.
c++ gcc this this-pointer
|
show 11 more comments
up vote
25
down vote
favorite
I asked myself whether the this
pointer could be overused since I usually use it every single time I refer to a member variable or function. I wondered if it could have performance impact since there must be a pointer which needs to be dereferenced every time. So I wrote some test code
struct A {
int x;
A(int X) {
x = X; /* And a second time with this->x = X; */
}
};
int main() {
A a(8);
return 0;
}
and surprisingly even with -O0
they output the exact same assembler code.
Also if I use a member function and call it in another member function it shows the same behavior. So is the this
pointer just a compile time thing and not an actual pointer? Or are there cases where this
is actually translated and dereferenced? I use GCC 4.4.3 btw.
c++ gcc this this-pointer
32
Bothx
andthis->x
access the member via the pointer to the object whose member it is. How else could they possibly work? Being able to writex
is merely syntactic sugar, a convenient shorthand.
– Igor Tandetnik
yesterday
7
" since i usually use it every single time i refer to a member variable or function" - why? It's almost always unnecessary to do this.
– Neil Butterworth
yesterday
7
@NeilButterworth because if you have a big class with numerous methods and members and if the methods are equally broad it is nice to immediately see where this function or variable might come from. Also it is just my style of coding which i prefer and now i wanted to know if it could have an impact on something.
– Yastanub
yesterday
4
Would it help you to think in these terms?: “When you typex = X;
the compiler automatically replaces it withthis->x = X;
”. It still glosses over details, but it’s not a bad mental model to explain why the two versions are the same.
– Euro Micelli
yesterday
4
Possible duplicate of Is there overhead using this-> in c++?
– underscore_d
yesterday
|
show 11 more comments
up vote
25
down vote
favorite
up vote
25
down vote
favorite
I asked myself whether the this
pointer could be overused since I usually use it every single time I refer to a member variable or function. I wondered if it could have performance impact since there must be a pointer which needs to be dereferenced every time. So I wrote some test code
struct A {
int x;
A(int X) {
x = X; /* And a second time with this->x = X; */
}
};
int main() {
A a(8);
return 0;
}
and surprisingly even with -O0
they output the exact same assembler code.
Also if I use a member function and call it in another member function it shows the same behavior. So is the this
pointer just a compile time thing and not an actual pointer? Or are there cases where this
is actually translated and dereferenced? I use GCC 4.4.3 btw.
c++ gcc this this-pointer
I asked myself whether the this
pointer could be overused since I usually use it every single time I refer to a member variable or function. I wondered if it could have performance impact since there must be a pointer which needs to be dereferenced every time. So I wrote some test code
struct A {
int x;
A(int X) {
x = X; /* And a second time with this->x = X; */
}
};
int main() {
A a(8);
return 0;
}
and surprisingly even with -O0
they output the exact same assembler code.
Also if I use a member function and call it in another member function it shows the same behavior. So is the this
pointer just a compile time thing and not an actual pointer? Or are there cases where this
is actually translated and dereferenced? I use GCC 4.4.3 btw.
c++ gcc this this-pointer
c++ gcc this this-pointer
edited yesterday
sds
38k1492164
38k1492164
asked yesterday
Yastanub
375210
375210
32
Bothx
andthis->x
access the member via the pointer to the object whose member it is. How else could they possibly work? Being able to writex
is merely syntactic sugar, a convenient shorthand.
– Igor Tandetnik
yesterday
7
" since i usually use it every single time i refer to a member variable or function" - why? It's almost always unnecessary to do this.
– Neil Butterworth
yesterday
7
@NeilButterworth because if you have a big class with numerous methods and members and if the methods are equally broad it is nice to immediately see where this function or variable might come from. Also it is just my style of coding which i prefer and now i wanted to know if it could have an impact on something.
– Yastanub
yesterday
4
Would it help you to think in these terms?: “When you typex = X;
the compiler automatically replaces it withthis->x = X;
”. It still glosses over details, but it’s not a bad mental model to explain why the two versions are the same.
– Euro Micelli
yesterday
4
Possible duplicate of Is there overhead using this-> in c++?
– underscore_d
yesterday
|
show 11 more comments
32
Bothx
andthis->x
access the member via the pointer to the object whose member it is. How else could they possibly work? Being able to writex
is merely syntactic sugar, a convenient shorthand.
– Igor Tandetnik
yesterday
7
" since i usually use it every single time i refer to a member variable or function" - why? It's almost always unnecessary to do this.
– Neil Butterworth
yesterday
7
@NeilButterworth because if you have a big class with numerous methods and members and if the methods are equally broad it is nice to immediately see where this function or variable might come from. Also it is just my style of coding which i prefer and now i wanted to know if it could have an impact on something.
– Yastanub
yesterday
4
Would it help you to think in these terms?: “When you typex = X;
the compiler automatically replaces it withthis->x = X;
”. It still glosses over details, but it’s not a bad mental model to explain why the two versions are the same.
– Euro Micelli
yesterday
4
Possible duplicate of Is there overhead using this-> in c++?
– underscore_d
yesterday
32
32
Both
x
and this->x
access the member via the pointer to the object whose member it is. How else could they possibly work? Being able to write x
is merely syntactic sugar, a convenient shorthand.– Igor Tandetnik
yesterday
Both
x
and this->x
access the member via the pointer to the object whose member it is. How else could they possibly work? Being able to write x
is merely syntactic sugar, a convenient shorthand.– Igor Tandetnik
yesterday
7
7
" since i usually use it every single time i refer to a member variable or function" - why? It's almost always unnecessary to do this.
– Neil Butterworth
yesterday
" since i usually use it every single time i refer to a member variable or function" - why? It's almost always unnecessary to do this.
– Neil Butterworth
yesterday
7
7
@NeilButterworth because if you have a big class with numerous methods and members and if the methods are equally broad it is nice to immediately see where this function or variable might come from. Also it is just my style of coding which i prefer and now i wanted to know if it could have an impact on something.
– Yastanub
yesterday
@NeilButterworth because if you have a big class with numerous methods and members and if the methods are equally broad it is nice to immediately see where this function or variable might come from. Also it is just my style of coding which i prefer and now i wanted to know if it could have an impact on something.
– Yastanub
yesterday
4
4
Would it help you to think in these terms?: “When you type
x = X;
the compiler automatically replaces it with this->x = X;
”. It still glosses over details, but it’s not a bad mental model to explain why the two versions are the same.– Euro Micelli
yesterday
Would it help you to think in these terms?: “When you type
x = X;
the compiler automatically replaces it with this->x = X;
”. It still glosses over details, but it’s not a bad mental model to explain why the two versions are the same.– Euro Micelli
yesterday
4
4
Possible duplicate of Is there overhead using this-> in c++?
– underscore_d
yesterday
Possible duplicate of Is there overhead using this-> in c++?
– underscore_d
yesterday
|
show 11 more comments
11 Answers
11
active
oldest
votes
up vote
63
down vote
accepted
So is the this pointer just a compile time thing and not an actual pointer?
It very much is a run time thing. It refers to the object on which the member function is invoked, naturally that object can exist at run time.
What is a compile time thing is how name lookup works. When a compiler encounters x = X
it must figure out what is this x
that is being assigned. So it looks it up, and finds the member variable. Since this->x
and x
refer to the same thing, naturally you get the same assembly output.
1
@Yastanub - That's kinda broad. But suffice it to say that if you need to pass a reference to your current object as an argument to another function, thenthis
is required (for instance, in the visitor design pattern). Name lookup is not the sole reason for its existence.
– StoryTeller
yesterday
7
@Yastanub - It's best not to speak in absolutes. It's there, and it has its uses.
– StoryTeller
yesterday
12
@Yastanub You probably need a good book.
– Passer By
yesterday
7
@Yastanubx
is syntactic sugar forthis->x
.
– John Kugelman
yesterday
5
@Yastanub At compile time, you know that x refers to, say, 8 bytes into an object. So the compiler basically translates eitherx
orthis->x
into*(this+8 bytes)
– Random832
yesterday
|
show 8 more comments
up vote
22
down vote
It is an actual pointer, as the standard specifies it (§12.2.2.1):
In the body of a non-static (12.2.1) member function, the keyword
this
is a prvalue expression whose value is the address of the object for which the function is called. The type ofthis
in a member function of a classX
isX*
.
this
is actually implicit every time you reference a non-static member variable or member function within a class own code. It is also needed (either when implicit or explicit) because the compiler needs to tie back the function or the variable to an actual object at runtime.
Using it explicitly is rarely useful, unless you need, for example, to disambiguate between a parameter and a member variable within a member function. Otherwise, without it the compiler will shadow the member variable with the parameter (See it live on Coliru).
6
You also need to explicitly writethis->
when accessing a member of a non-dependent base type from a template member. Not often needed, and a good compiler will diagnose exactly when you forget it, but worth mentioning.
– Toby Speight
yesterday
It can also be very useful to write "this->" when developing with an IDE, because the IDE can then provide a list of members to select from. (Personally, I tend not to use an IDE, but if one chooses to, taking advantage of it seems sensible.)
– Martin Bonner
18 hours ago
1
"Using it explicitly is rarely useful", from the compiler perspective, true; From a human perspective, some teams will enforce this as a style rule to prevent human-error introduced bugs.
– Tezra
15 hours ago
add a comment |
up vote
14
down vote
this
always has to exist when you are in a non-static method. Whether you explicitly use it or not, you have to have a reference to the current instance, and this is what this
gives you.
In both cases, you are going to access memory through the this
pointer. It's just that you can omit it in some cases.
Essentially, syntactical sugar (whether by inclusion or omission, its a shortcut).
– Draco18s
yesterday
add a comment |
up vote
13
down vote
This is almost a duplicate of How do objects work in x86 at the assembly level?, where I comment the asm output of some examples, including showing which register the this
pointer was passed in.
In asm, this
works exactly like a hidden first arg, so both the member-function foo::add(int)
and the non-member add
which takes an explicit foo*
first arg compile to exactly the same asm.
struct foo {
int m;
void add(int a); // not inline so we get a stand-alone definition emitted
};
void foo::add(int a) {
this->m += a;
}
void add(foo *obj, int a) {
obj->m += a;
}
On the Godbolt compiler explorer, compiling for x86-64 with the System V ABI (first arg in RDI, second in RSI), we get:
# gcc8.2 -O3
foo::add(int):
add DWORD PTR [rdi], esi # memory-destination add
ret
add(foo*, int):
add DWORD PTR [rdi], esi
ret
I use GCC 4.4.3
That was released in January 2010, so it's missing nearly a decade of improvements to the optimizer, and to error messages. The gcc7 series has been out and stable for a while. Expect missed optimizations with such an old compiler, especially for modern instruction sets like AVX.
add a comment |
up vote
9
down vote
After compilation, every symbol is just an address, so it can't be a run-time issue.
Any member symbol is compiled to an offset in the current class anyway, even if you didn't use this
.
When name
is used in C++ it can be one of the following.
- In the global namespace (like
::name
), or in the current namespace, or in the used namespace (whenusing namespace ...
been used) - In the current class
- Local definition, in upper block
- Local definition, in current block
Therefore, when you write code, the compiler should scan each, in a manner to look for the symbol name, from the current block and up to the global namespace.
Using this->name
helps the compiler to narrow the search for name
to only look for it in the current class scope, meaning it skips local definitions, and if not found in class scope, do not look for it in the global scope.
add a comment |
up vote
5
down vote
Here is a simple example how "this" could be useful during runtime:
#include <vector>
#include <string>
#include <iostream>
class A;
typedef std::vector<A*> News;
class A
{
public:
A(const char* n): name(n){}
std::string name;
void subscribe(News& n)
{
n.push_back(this);
}
};
int main()
{
A a1("Alex"), a2("Bob"), a3("Chris");
News news;
a1.subscribe(news);
a3.subscribe(news);
std::cout << "Subscriber:";
for(auto& a: news)
{
std::cout << " " << a->name;
}
return 0;
}
add a comment |
up vote
3
down vote
since I usually use it every single time I refer to a member variable or function.
You always use this
when you refer to a member variable or function. There is simply no other way to reach members. The only choice is implicit vs explicit notation.
Let's go back to see how it was done before this
to understand what this
is.
Without OOP:
struct A {
int x;
};
void foo(A* that) {
bar(that->x)
}
With OOP but writing this
explicitly
struct A {
int x;
void foo(void) {
bar(this->x)
}
};
using shorter notation:
struct A {
int x;
void foo(void) {
bar(x)
}
};
But the difference is only in source code. All are compiled to same thing. If you create a member method, the compiler will create a pointer argument for you and name it "this". If you omit this->
when referring to a member, the compiler is clever just enough to insert it for you most of the time. That's it. The only difference is 6 less letters in the source.
Writing this
explicitly makes sense when there is an ambiguity, namely another variable named just like your member variable:
struct A {
int x;
A(int x) {
this->x = x
}
};
There are some instances, like __thiscall, where OO and non-OO code may end bit different in asm, but whenever the pointer is passed on stack and then optimized to a register or in ECX from the very beginning doesn't make it "not a pointer".
add a comment |
up vote
2
down vote
Your machine does not know anything about class methods, they are normal functions under the hood.
Hence methods have to be implemented by always passing a pointer to the current object, it's just implicit in C++, i.e. T Class::method(...)
is just syntactic sugar for T Class_Method(Class* this, ...)
.
Other languages like Python or Lua choose to make it explicit and modern object-oriented C APIs like Vulkan (unlike OpenGL) use a similar pattern.
add a comment |
up vote
2
down vote
"this" can also safeguard against shadowing by a function parameter, for example:
class Vector {
public:
double x,y,z;
void SetLocation(double x, double y, double z);
};
void Vector::SetLocation(double x, double y, double z) {
this->x = x; //Passed parameter assigned to member variable
this->y = y;
this->z = z;
}
(Obviously, writing such code is discouraged.)
Usually shadowing comes up as an issue when the member variable is being shadowed by an introduced local variable (where you normally aren't thinking of what is in the global scope), so use of this->x is encouraged to prevent such modification bugs.
– Tezra
15 hours ago
Yeah unfortunately -Wshadow is not enabled with -Wall. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
– Trass3r
6 hours ago
add a comment |
up vote
2
down vote
if the compiler inlines a member function that is called with static rather than dynamic binding, it might be able to optimize away the this
pointer. Take this simple example:
#include <iostream>
using std::cout;
using std::endl;
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int main(void)
{
example e;
e.foo(10);
cout << e.foo() << endl;
}
GCC 7.3.0 with the -march=x86-64 -O -S
flag is able to compile cout << e.foo()
to three instructions:
movl $10, %esi
leaq _ZSt4cout(%rip), %rdi
call _ZNSolsEi@PLT
This is a call to std::ostream::operator<<
. Remember that cout << e.foo();
is syntactic sugar for std::ostream::operator<< (cout, e.foo());
. And operator<<(int)
could be written two ways: static operator<< (ostream&, int)
, as a non-member function, where the operand on the left is an explicit parameter, or operator<<(int)
, as a member function, where it’s implicitly this
.
The compiler was able to deduce that e.foo()
will always be the constant 10
. Since the 64-bit x86 calling convention is to pass function arguments in registers, that compiles down to the single movl
instruction, which sets the second function parameter to 10
. The leaq
instruction sets the first argument (which might be an explicit ostream&
or the implicit this
) to &cout
. Then the program makes a call
to the function.
In more complex cases, though—such as if you have a function taking an example&
as a parameter—the compiler needs to look up this
, as this
is what tells the program which instance it’s working with, and therefore, which instance’s x
data member to look up.
Consider this example:
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int bar( const example& e )
{
return e.foo();
}
The function bar()
gets compiled to a bit of boilerplate and the instruction:
movl (%rdi), %eax
ret
You remember from the previous example that %rdi
on x86-64 is the first function argument, the implicit this
pointer for the call to e.foo()
. Putting it in parentheses, (%rdi)
, means look up the variable at that location. (Since the only data in an example
instance is x
, &e.x
happens to be the same as &e
in this case.) Moving the contents to %eax
sets the return value.
In this case, the compiler needed the implicit this
argument to foo(/* example* this */)
to be able to find &e
and therefore &e.x
. In fact, inside a member function (that isn’t static
), x
, this->x
and (*this).x
all mean the same thing.
add a comment |
up vote
1
down vote
this
is a pointer. It's like an implicit parameter that's part of every method. You could imagine using plain C functions and writing code like:
Socket makeSocket(int port) { ... }
void send(Socket *this, Value v) { ... }
Value receive(Socket *this) { ... }
Socket *mySocket = makeSocket(1234);
send(mySocket, someValue); // The subject, `mySocket`, is passed in as a param called "this", explicitly
Value newData = receive(socket);
In C++, similar code might look like:
mySocket.send(someValue); // The subject, `mySocket`, is passed in as a param called "this"
Value newData = mySocket.receive();
add a comment |
11 Answers
11
active
oldest
votes
11 Answers
11
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
63
down vote
accepted
So is the this pointer just a compile time thing and not an actual pointer?
It very much is a run time thing. It refers to the object on which the member function is invoked, naturally that object can exist at run time.
What is a compile time thing is how name lookup works. When a compiler encounters x = X
it must figure out what is this x
that is being assigned. So it looks it up, and finds the member variable. Since this->x
and x
refer to the same thing, naturally you get the same assembly output.
1
@Yastanub - That's kinda broad. But suffice it to say that if you need to pass a reference to your current object as an argument to another function, thenthis
is required (for instance, in the visitor design pattern). Name lookup is not the sole reason for its existence.
– StoryTeller
yesterday
7
@Yastanub - It's best not to speak in absolutes. It's there, and it has its uses.
– StoryTeller
yesterday
12
@Yastanub You probably need a good book.
– Passer By
yesterday
7
@Yastanubx
is syntactic sugar forthis->x
.
– John Kugelman
yesterday
5
@Yastanub At compile time, you know that x refers to, say, 8 bytes into an object. So the compiler basically translates eitherx
orthis->x
into*(this+8 bytes)
– Random832
yesterday
|
show 8 more comments
up vote
63
down vote
accepted
So is the this pointer just a compile time thing and not an actual pointer?
It very much is a run time thing. It refers to the object on which the member function is invoked, naturally that object can exist at run time.
What is a compile time thing is how name lookup works. When a compiler encounters x = X
it must figure out what is this x
that is being assigned. So it looks it up, and finds the member variable. Since this->x
and x
refer to the same thing, naturally you get the same assembly output.
1
@Yastanub - That's kinda broad. But suffice it to say that if you need to pass a reference to your current object as an argument to another function, thenthis
is required (for instance, in the visitor design pattern). Name lookup is not the sole reason for its existence.
– StoryTeller
yesterday
7
@Yastanub - It's best not to speak in absolutes. It's there, and it has its uses.
– StoryTeller
yesterday
12
@Yastanub You probably need a good book.
– Passer By
yesterday
7
@Yastanubx
is syntactic sugar forthis->x
.
– John Kugelman
yesterday
5
@Yastanub At compile time, you know that x refers to, say, 8 bytes into an object. So the compiler basically translates eitherx
orthis->x
into*(this+8 bytes)
– Random832
yesterday
|
show 8 more comments
up vote
63
down vote
accepted
up vote
63
down vote
accepted
So is the this pointer just a compile time thing and not an actual pointer?
It very much is a run time thing. It refers to the object on which the member function is invoked, naturally that object can exist at run time.
What is a compile time thing is how name lookup works. When a compiler encounters x = X
it must figure out what is this x
that is being assigned. So it looks it up, and finds the member variable. Since this->x
and x
refer to the same thing, naturally you get the same assembly output.
So is the this pointer just a compile time thing and not an actual pointer?
It very much is a run time thing. It refers to the object on which the member function is invoked, naturally that object can exist at run time.
What is a compile time thing is how name lookup works. When a compiler encounters x = X
it must figure out what is this x
that is being assigned. So it looks it up, and finds the member variable. Since this->x
and x
refer to the same thing, naturally you get the same assembly output.
answered yesterday
StoryTeller
88.4k12176244
88.4k12176244
1
@Yastanub - That's kinda broad. But suffice it to say that if you need to pass a reference to your current object as an argument to another function, thenthis
is required (for instance, in the visitor design pattern). Name lookup is not the sole reason for its existence.
– StoryTeller
yesterday
7
@Yastanub - It's best not to speak in absolutes. It's there, and it has its uses.
– StoryTeller
yesterday
12
@Yastanub You probably need a good book.
– Passer By
yesterday
7
@Yastanubx
is syntactic sugar forthis->x
.
– John Kugelman
yesterday
5
@Yastanub At compile time, you know that x refers to, say, 8 bytes into an object. So the compiler basically translates eitherx
orthis->x
into*(this+8 bytes)
– Random832
yesterday
|
show 8 more comments
1
@Yastanub - That's kinda broad. But suffice it to say that if you need to pass a reference to your current object as an argument to another function, thenthis
is required (for instance, in the visitor design pattern). Name lookup is not the sole reason for its existence.
– StoryTeller
yesterday
7
@Yastanub - It's best not to speak in absolutes. It's there, and it has its uses.
– StoryTeller
yesterday
12
@Yastanub You probably need a good book.
– Passer By
yesterday
7
@Yastanubx
is syntactic sugar forthis->x
.
– John Kugelman
yesterday
5
@Yastanub At compile time, you know that x refers to, say, 8 bytes into an object. So the compiler basically translates eitherx
orthis->x
into*(this+8 bytes)
– Random832
yesterday
1
1
@Yastanub - That's kinda broad. But suffice it to say that if you need to pass a reference to your current object as an argument to another function, then
this
is required (for instance, in the visitor design pattern). Name lookup is not the sole reason for its existence.– StoryTeller
yesterday
@Yastanub - That's kinda broad. But suffice it to say that if you need to pass a reference to your current object as an argument to another function, then
this
is required (for instance, in the visitor design pattern). Name lookup is not the sole reason for its existence.– StoryTeller
yesterday
7
7
@Yastanub - It's best not to speak in absolutes. It's there, and it has its uses.
– StoryTeller
yesterday
@Yastanub - It's best not to speak in absolutes. It's there, and it has its uses.
– StoryTeller
yesterday
12
12
@Yastanub You probably need a good book.
– Passer By
yesterday
@Yastanub You probably need a good book.
– Passer By
yesterday
7
7
@Yastanub
x
is syntactic sugar for this->x
.– John Kugelman
yesterday
@Yastanub
x
is syntactic sugar for this->x
.– John Kugelman
yesterday
5
5
@Yastanub At compile time, you know that x refers to, say, 8 bytes into an object. So the compiler basically translates either
x
or this->x
into *(this+8 bytes)
– Random832
yesterday
@Yastanub At compile time, you know that x refers to, say, 8 bytes into an object. So the compiler basically translates either
x
or this->x
into *(this+8 bytes)
– Random832
yesterday
|
show 8 more comments
up vote
22
down vote
It is an actual pointer, as the standard specifies it (§12.2.2.1):
In the body of a non-static (12.2.1) member function, the keyword
this
is a prvalue expression whose value is the address of the object for which the function is called. The type ofthis
in a member function of a classX
isX*
.
this
is actually implicit every time you reference a non-static member variable or member function within a class own code. It is also needed (either when implicit or explicit) because the compiler needs to tie back the function or the variable to an actual object at runtime.
Using it explicitly is rarely useful, unless you need, for example, to disambiguate between a parameter and a member variable within a member function. Otherwise, without it the compiler will shadow the member variable with the parameter (See it live on Coliru).
6
You also need to explicitly writethis->
when accessing a member of a non-dependent base type from a template member. Not often needed, and a good compiler will diagnose exactly when you forget it, but worth mentioning.
– Toby Speight
yesterday
It can also be very useful to write "this->" when developing with an IDE, because the IDE can then provide a list of members to select from. (Personally, I tend not to use an IDE, but if one chooses to, taking advantage of it seems sensible.)
– Martin Bonner
18 hours ago
1
"Using it explicitly is rarely useful", from the compiler perspective, true; From a human perspective, some teams will enforce this as a style rule to prevent human-error introduced bugs.
– Tezra
15 hours ago
add a comment |
up vote
22
down vote
It is an actual pointer, as the standard specifies it (§12.2.2.1):
In the body of a non-static (12.2.1) member function, the keyword
this
is a prvalue expression whose value is the address of the object for which the function is called. The type ofthis
in a member function of a classX
isX*
.
this
is actually implicit every time you reference a non-static member variable or member function within a class own code. It is also needed (either when implicit or explicit) because the compiler needs to tie back the function or the variable to an actual object at runtime.
Using it explicitly is rarely useful, unless you need, for example, to disambiguate between a parameter and a member variable within a member function. Otherwise, without it the compiler will shadow the member variable with the parameter (See it live on Coliru).
6
You also need to explicitly writethis->
when accessing a member of a non-dependent base type from a template member. Not often needed, and a good compiler will diagnose exactly when you forget it, but worth mentioning.
– Toby Speight
yesterday
It can also be very useful to write "this->" when developing with an IDE, because the IDE can then provide a list of members to select from. (Personally, I tend not to use an IDE, but if one chooses to, taking advantage of it seems sensible.)
– Martin Bonner
18 hours ago
1
"Using it explicitly is rarely useful", from the compiler perspective, true; From a human perspective, some teams will enforce this as a style rule to prevent human-error introduced bugs.
– Tezra
15 hours ago
add a comment |
up vote
22
down vote
up vote
22
down vote
It is an actual pointer, as the standard specifies it (§12.2.2.1):
In the body of a non-static (12.2.1) member function, the keyword
this
is a prvalue expression whose value is the address of the object for which the function is called. The type ofthis
in a member function of a classX
isX*
.
this
is actually implicit every time you reference a non-static member variable or member function within a class own code. It is also needed (either when implicit or explicit) because the compiler needs to tie back the function or the variable to an actual object at runtime.
Using it explicitly is rarely useful, unless you need, for example, to disambiguate between a parameter and a member variable within a member function. Otherwise, without it the compiler will shadow the member variable with the parameter (See it live on Coliru).
It is an actual pointer, as the standard specifies it (§12.2.2.1):
In the body of a non-static (12.2.1) member function, the keyword
this
is a prvalue expression whose value is the address of the object for which the function is called. The type ofthis
in a member function of a classX
isX*
.
this
is actually implicit every time you reference a non-static member variable or member function within a class own code. It is also needed (either when implicit or explicit) because the compiler needs to tie back the function or the variable to an actual object at runtime.
Using it explicitly is rarely useful, unless you need, for example, to disambiguate between a parameter and a member variable within a member function. Otherwise, without it the compiler will shadow the member variable with the parameter (See it live on Coliru).
edited yesterday
Toby Speight
15.8k133965
15.8k133965
answered yesterday
JBL
9,51433567
9,51433567
6
You also need to explicitly writethis->
when accessing a member of a non-dependent base type from a template member. Not often needed, and a good compiler will diagnose exactly when you forget it, but worth mentioning.
– Toby Speight
yesterday
It can also be very useful to write "this->" when developing with an IDE, because the IDE can then provide a list of members to select from. (Personally, I tend not to use an IDE, but if one chooses to, taking advantage of it seems sensible.)
– Martin Bonner
18 hours ago
1
"Using it explicitly is rarely useful", from the compiler perspective, true; From a human perspective, some teams will enforce this as a style rule to prevent human-error introduced bugs.
– Tezra
15 hours ago
add a comment |
6
You also need to explicitly writethis->
when accessing a member of a non-dependent base type from a template member. Not often needed, and a good compiler will diagnose exactly when you forget it, but worth mentioning.
– Toby Speight
yesterday
It can also be very useful to write "this->" when developing with an IDE, because the IDE can then provide a list of members to select from. (Personally, I tend not to use an IDE, but if one chooses to, taking advantage of it seems sensible.)
– Martin Bonner
18 hours ago
1
"Using it explicitly is rarely useful", from the compiler perspective, true; From a human perspective, some teams will enforce this as a style rule to prevent human-error introduced bugs.
– Tezra
15 hours ago
6
6
You also need to explicitly write
this->
when accessing a member of a non-dependent base type from a template member. Not often needed, and a good compiler will diagnose exactly when you forget it, but worth mentioning.– Toby Speight
yesterday
You also need to explicitly write
this->
when accessing a member of a non-dependent base type from a template member. Not often needed, and a good compiler will diagnose exactly when you forget it, but worth mentioning.– Toby Speight
yesterday
It can also be very useful to write "this->" when developing with an IDE, because the IDE can then provide a list of members to select from. (Personally, I tend not to use an IDE, but if one chooses to, taking advantage of it seems sensible.)
– Martin Bonner
18 hours ago
It can also be very useful to write "this->" when developing with an IDE, because the IDE can then provide a list of members to select from. (Personally, I tend not to use an IDE, but if one chooses to, taking advantage of it seems sensible.)
– Martin Bonner
18 hours ago
1
1
"Using it explicitly is rarely useful", from the compiler perspective, true; From a human perspective, some teams will enforce this as a style rule to prevent human-error introduced bugs.
– Tezra
15 hours ago
"Using it explicitly is rarely useful", from the compiler perspective, true; From a human perspective, some teams will enforce this as a style rule to prevent human-error introduced bugs.
– Tezra
15 hours ago
add a comment |
up vote
14
down vote
this
always has to exist when you are in a non-static method. Whether you explicitly use it or not, you have to have a reference to the current instance, and this is what this
gives you.
In both cases, you are going to access memory through the this
pointer. It's just that you can omit it in some cases.
Essentially, syntactical sugar (whether by inclusion or omission, its a shortcut).
– Draco18s
yesterday
add a comment |
up vote
14
down vote
this
always has to exist when you are in a non-static method. Whether you explicitly use it or not, you have to have a reference to the current instance, and this is what this
gives you.
In both cases, you are going to access memory through the this
pointer. It's just that you can omit it in some cases.
Essentially, syntactical sugar (whether by inclusion or omission, its a shortcut).
– Draco18s
yesterday
add a comment |
up vote
14
down vote
up vote
14
down vote
this
always has to exist when you are in a non-static method. Whether you explicitly use it or not, you have to have a reference to the current instance, and this is what this
gives you.
In both cases, you are going to access memory through the this
pointer. It's just that you can omit it in some cases.
this
always has to exist when you are in a non-static method. Whether you explicitly use it or not, you have to have a reference to the current instance, and this is what this
gives you.
In both cases, you are going to access memory through the this
pointer. It's just that you can omit it in some cases.
edited yesterday
answered yesterday
Matthieu Brucher
5,2061128
5,2061128
Essentially, syntactical sugar (whether by inclusion or omission, its a shortcut).
– Draco18s
yesterday
add a comment |
Essentially, syntactical sugar (whether by inclusion or omission, its a shortcut).
– Draco18s
yesterday
Essentially, syntactical sugar (whether by inclusion or omission, its a shortcut).
– Draco18s
yesterday
Essentially, syntactical sugar (whether by inclusion or omission, its a shortcut).
– Draco18s
yesterday
add a comment |
up vote
13
down vote
This is almost a duplicate of How do objects work in x86 at the assembly level?, where I comment the asm output of some examples, including showing which register the this
pointer was passed in.
In asm, this
works exactly like a hidden first arg, so both the member-function foo::add(int)
and the non-member add
which takes an explicit foo*
first arg compile to exactly the same asm.
struct foo {
int m;
void add(int a); // not inline so we get a stand-alone definition emitted
};
void foo::add(int a) {
this->m += a;
}
void add(foo *obj, int a) {
obj->m += a;
}
On the Godbolt compiler explorer, compiling for x86-64 with the System V ABI (first arg in RDI, second in RSI), we get:
# gcc8.2 -O3
foo::add(int):
add DWORD PTR [rdi], esi # memory-destination add
ret
add(foo*, int):
add DWORD PTR [rdi], esi
ret
I use GCC 4.4.3
That was released in January 2010, so it's missing nearly a decade of improvements to the optimizer, and to error messages. The gcc7 series has been out and stable for a while. Expect missed optimizations with such an old compiler, especially for modern instruction sets like AVX.
add a comment |
up vote
13
down vote
This is almost a duplicate of How do objects work in x86 at the assembly level?, where I comment the asm output of some examples, including showing which register the this
pointer was passed in.
In asm, this
works exactly like a hidden first arg, so both the member-function foo::add(int)
and the non-member add
which takes an explicit foo*
first arg compile to exactly the same asm.
struct foo {
int m;
void add(int a); // not inline so we get a stand-alone definition emitted
};
void foo::add(int a) {
this->m += a;
}
void add(foo *obj, int a) {
obj->m += a;
}
On the Godbolt compiler explorer, compiling for x86-64 with the System V ABI (first arg in RDI, second in RSI), we get:
# gcc8.2 -O3
foo::add(int):
add DWORD PTR [rdi], esi # memory-destination add
ret
add(foo*, int):
add DWORD PTR [rdi], esi
ret
I use GCC 4.4.3
That was released in January 2010, so it's missing nearly a decade of improvements to the optimizer, and to error messages. The gcc7 series has been out and stable for a while. Expect missed optimizations with such an old compiler, especially for modern instruction sets like AVX.
add a comment |
up vote
13
down vote
up vote
13
down vote
This is almost a duplicate of How do objects work in x86 at the assembly level?, where I comment the asm output of some examples, including showing which register the this
pointer was passed in.
In asm, this
works exactly like a hidden first arg, so both the member-function foo::add(int)
and the non-member add
which takes an explicit foo*
first arg compile to exactly the same asm.
struct foo {
int m;
void add(int a); // not inline so we get a stand-alone definition emitted
};
void foo::add(int a) {
this->m += a;
}
void add(foo *obj, int a) {
obj->m += a;
}
On the Godbolt compiler explorer, compiling for x86-64 with the System V ABI (first arg in RDI, second in RSI), we get:
# gcc8.2 -O3
foo::add(int):
add DWORD PTR [rdi], esi # memory-destination add
ret
add(foo*, int):
add DWORD PTR [rdi], esi
ret
I use GCC 4.4.3
That was released in January 2010, so it's missing nearly a decade of improvements to the optimizer, and to error messages. The gcc7 series has been out and stable for a while. Expect missed optimizations with such an old compiler, especially for modern instruction sets like AVX.
This is almost a duplicate of How do objects work in x86 at the assembly level?, where I comment the asm output of some examples, including showing which register the this
pointer was passed in.
In asm, this
works exactly like a hidden first arg, so both the member-function foo::add(int)
and the non-member add
which takes an explicit foo*
first arg compile to exactly the same asm.
struct foo {
int m;
void add(int a); // not inline so we get a stand-alone definition emitted
};
void foo::add(int a) {
this->m += a;
}
void add(foo *obj, int a) {
obj->m += a;
}
On the Godbolt compiler explorer, compiling for x86-64 with the System V ABI (first arg in RDI, second in RSI), we get:
# gcc8.2 -O3
foo::add(int):
add DWORD PTR [rdi], esi # memory-destination add
ret
add(foo*, int):
add DWORD PTR [rdi], esi
ret
I use GCC 4.4.3
That was released in January 2010, so it's missing nearly a decade of improvements to the optimizer, and to error messages. The gcc7 series has been out and stable for a while. Expect missed optimizations with such an old compiler, especially for modern instruction sets like AVX.
answered yesterday
Peter Cordes
114k16173296
114k16173296
add a comment |
add a comment |
up vote
9
down vote
After compilation, every symbol is just an address, so it can't be a run-time issue.
Any member symbol is compiled to an offset in the current class anyway, even if you didn't use this
.
When name
is used in C++ it can be one of the following.
- In the global namespace (like
::name
), or in the current namespace, or in the used namespace (whenusing namespace ...
been used) - In the current class
- Local definition, in upper block
- Local definition, in current block
Therefore, when you write code, the compiler should scan each, in a manner to look for the symbol name, from the current block and up to the global namespace.
Using this->name
helps the compiler to narrow the search for name
to only look for it in the current class scope, meaning it skips local definitions, and if not found in class scope, do not look for it in the global scope.
add a comment |
up vote
9
down vote
After compilation, every symbol is just an address, so it can't be a run-time issue.
Any member symbol is compiled to an offset in the current class anyway, even if you didn't use this
.
When name
is used in C++ it can be one of the following.
- In the global namespace (like
::name
), or in the current namespace, or in the used namespace (whenusing namespace ...
been used) - In the current class
- Local definition, in upper block
- Local definition, in current block
Therefore, when you write code, the compiler should scan each, in a manner to look for the symbol name, from the current block and up to the global namespace.
Using this->name
helps the compiler to narrow the search for name
to only look for it in the current class scope, meaning it skips local definitions, and if not found in class scope, do not look for it in the global scope.
add a comment |
up vote
9
down vote
up vote
9
down vote
After compilation, every symbol is just an address, so it can't be a run-time issue.
Any member symbol is compiled to an offset in the current class anyway, even if you didn't use this
.
When name
is used in C++ it can be one of the following.
- In the global namespace (like
::name
), or in the current namespace, or in the used namespace (whenusing namespace ...
been used) - In the current class
- Local definition, in upper block
- Local definition, in current block
Therefore, when you write code, the compiler should scan each, in a manner to look for the symbol name, from the current block and up to the global namespace.
Using this->name
helps the compiler to narrow the search for name
to only look for it in the current class scope, meaning it skips local definitions, and if not found in class scope, do not look for it in the global scope.
After compilation, every symbol is just an address, so it can't be a run-time issue.
Any member symbol is compiled to an offset in the current class anyway, even if you didn't use this
.
When name
is used in C++ it can be one of the following.
- In the global namespace (like
::name
), or in the current namespace, or in the used namespace (whenusing namespace ...
been used) - In the current class
- Local definition, in upper block
- Local definition, in current block
Therefore, when you write code, the compiler should scan each, in a manner to look for the symbol name, from the current block and up to the global namespace.
Using this->name
helps the compiler to narrow the search for name
to only look for it in the current class scope, meaning it skips local definitions, and if not found in class scope, do not look for it in the global scope.
edited yesterday
Peter Mortensen
13.3k1983111
13.3k1983111
answered yesterday
SHR
5,47242240
5,47242240
add a comment |
add a comment |
up vote
5
down vote
Here is a simple example how "this" could be useful during runtime:
#include <vector>
#include <string>
#include <iostream>
class A;
typedef std::vector<A*> News;
class A
{
public:
A(const char* n): name(n){}
std::string name;
void subscribe(News& n)
{
n.push_back(this);
}
};
int main()
{
A a1("Alex"), a2("Bob"), a3("Chris");
News news;
a1.subscribe(news);
a3.subscribe(news);
std::cout << "Subscriber:";
for(auto& a: news)
{
std::cout << " " << a->name;
}
return 0;
}
add a comment |
up vote
5
down vote
Here is a simple example how "this" could be useful during runtime:
#include <vector>
#include <string>
#include <iostream>
class A;
typedef std::vector<A*> News;
class A
{
public:
A(const char* n): name(n){}
std::string name;
void subscribe(News& n)
{
n.push_back(this);
}
};
int main()
{
A a1("Alex"), a2("Bob"), a3("Chris");
News news;
a1.subscribe(news);
a3.subscribe(news);
std::cout << "Subscriber:";
for(auto& a: news)
{
std::cout << " " << a->name;
}
return 0;
}
add a comment |
up vote
5
down vote
up vote
5
down vote
Here is a simple example how "this" could be useful during runtime:
#include <vector>
#include <string>
#include <iostream>
class A;
typedef std::vector<A*> News;
class A
{
public:
A(const char* n): name(n){}
std::string name;
void subscribe(News& n)
{
n.push_back(this);
}
};
int main()
{
A a1("Alex"), a2("Bob"), a3("Chris");
News news;
a1.subscribe(news);
a3.subscribe(news);
std::cout << "Subscriber:";
for(auto& a: news)
{
std::cout << " " << a->name;
}
return 0;
}
Here is a simple example how "this" could be useful during runtime:
#include <vector>
#include <string>
#include <iostream>
class A;
typedef std::vector<A*> News;
class A
{
public:
A(const char* n): name(n){}
std::string name;
void subscribe(News& n)
{
n.push_back(this);
}
};
int main()
{
A a1("Alex"), a2("Bob"), a3("Chris");
News news;
a1.subscribe(news);
a3.subscribe(news);
std::cout << "Subscriber:";
for(auto& a: news)
{
std::cout << " " << a->name;
}
return 0;
}
answered yesterday
Helmut Zeisel
663
663
add a comment |
add a comment |
up vote
3
down vote
since I usually use it every single time I refer to a member variable or function.
You always use this
when you refer to a member variable or function. There is simply no other way to reach members. The only choice is implicit vs explicit notation.
Let's go back to see how it was done before this
to understand what this
is.
Without OOP:
struct A {
int x;
};
void foo(A* that) {
bar(that->x)
}
With OOP but writing this
explicitly
struct A {
int x;
void foo(void) {
bar(this->x)
}
};
using shorter notation:
struct A {
int x;
void foo(void) {
bar(x)
}
};
But the difference is only in source code. All are compiled to same thing. If you create a member method, the compiler will create a pointer argument for you and name it "this". If you omit this->
when referring to a member, the compiler is clever just enough to insert it for you most of the time. That's it. The only difference is 6 less letters in the source.
Writing this
explicitly makes sense when there is an ambiguity, namely another variable named just like your member variable:
struct A {
int x;
A(int x) {
this->x = x
}
};
There are some instances, like __thiscall, where OO and non-OO code may end bit different in asm, but whenever the pointer is passed on stack and then optimized to a register or in ECX from the very beginning doesn't make it "not a pointer".
add a comment |
up vote
3
down vote
since I usually use it every single time I refer to a member variable or function.
You always use this
when you refer to a member variable or function. There is simply no other way to reach members. The only choice is implicit vs explicit notation.
Let's go back to see how it was done before this
to understand what this
is.
Without OOP:
struct A {
int x;
};
void foo(A* that) {
bar(that->x)
}
With OOP but writing this
explicitly
struct A {
int x;
void foo(void) {
bar(this->x)
}
};
using shorter notation:
struct A {
int x;
void foo(void) {
bar(x)
}
};
But the difference is only in source code. All are compiled to same thing. If you create a member method, the compiler will create a pointer argument for you and name it "this". If you omit this->
when referring to a member, the compiler is clever just enough to insert it for you most of the time. That's it. The only difference is 6 less letters in the source.
Writing this
explicitly makes sense when there is an ambiguity, namely another variable named just like your member variable:
struct A {
int x;
A(int x) {
this->x = x
}
};
There are some instances, like __thiscall, where OO and non-OO code may end bit different in asm, but whenever the pointer is passed on stack and then optimized to a register or in ECX from the very beginning doesn't make it "not a pointer".
add a comment |
up vote
3
down vote
up vote
3
down vote
since I usually use it every single time I refer to a member variable or function.
You always use this
when you refer to a member variable or function. There is simply no other way to reach members. The only choice is implicit vs explicit notation.
Let's go back to see how it was done before this
to understand what this
is.
Without OOP:
struct A {
int x;
};
void foo(A* that) {
bar(that->x)
}
With OOP but writing this
explicitly
struct A {
int x;
void foo(void) {
bar(this->x)
}
};
using shorter notation:
struct A {
int x;
void foo(void) {
bar(x)
}
};
But the difference is only in source code. All are compiled to same thing. If you create a member method, the compiler will create a pointer argument for you and name it "this". If you omit this->
when referring to a member, the compiler is clever just enough to insert it for you most of the time. That's it. The only difference is 6 less letters in the source.
Writing this
explicitly makes sense when there is an ambiguity, namely another variable named just like your member variable:
struct A {
int x;
A(int x) {
this->x = x
}
};
There are some instances, like __thiscall, where OO and non-OO code may end bit different in asm, but whenever the pointer is passed on stack and then optimized to a register or in ECX from the very beginning doesn't make it "not a pointer".
since I usually use it every single time I refer to a member variable or function.
You always use this
when you refer to a member variable or function. There is simply no other way to reach members. The only choice is implicit vs explicit notation.
Let's go back to see how it was done before this
to understand what this
is.
Without OOP:
struct A {
int x;
};
void foo(A* that) {
bar(that->x)
}
With OOP but writing this
explicitly
struct A {
int x;
void foo(void) {
bar(this->x)
}
};
using shorter notation:
struct A {
int x;
void foo(void) {
bar(x)
}
};
But the difference is only in source code. All are compiled to same thing. If you create a member method, the compiler will create a pointer argument for you and name it "this". If you omit this->
when referring to a member, the compiler is clever just enough to insert it for you most of the time. That's it. The only difference is 6 less letters in the source.
Writing this
explicitly makes sense when there is an ambiguity, namely another variable named just like your member variable:
struct A {
int x;
A(int x) {
this->x = x
}
};
There are some instances, like __thiscall, where OO and non-OO code may end bit different in asm, but whenever the pointer is passed on stack and then optimized to a register or in ECX from the very beginning doesn't make it "not a pointer".
answered 20 hours ago
Agent_L
3,1711620
3,1711620
add a comment |
add a comment |
up vote
2
down vote
Your machine does not know anything about class methods, they are normal functions under the hood.
Hence methods have to be implemented by always passing a pointer to the current object, it's just implicit in C++, i.e. T Class::method(...)
is just syntactic sugar for T Class_Method(Class* this, ...)
.
Other languages like Python or Lua choose to make it explicit and modern object-oriented C APIs like Vulkan (unlike OpenGL) use a similar pattern.
add a comment |
up vote
2
down vote
Your machine does not know anything about class methods, they are normal functions under the hood.
Hence methods have to be implemented by always passing a pointer to the current object, it's just implicit in C++, i.e. T Class::method(...)
is just syntactic sugar for T Class_Method(Class* this, ...)
.
Other languages like Python or Lua choose to make it explicit and modern object-oriented C APIs like Vulkan (unlike OpenGL) use a similar pattern.
add a comment |
up vote
2
down vote
up vote
2
down vote
Your machine does not know anything about class methods, they are normal functions under the hood.
Hence methods have to be implemented by always passing a pointer to the current object, it's just implicit in C++, i.e. T Class::method(...)
is just syntactic sugar for T Class_Method(Class* this, ...)
.
Other languages like Python or Lua choose to make it explicit and modern object-oriented C APIs like Vulkan (unlike OpenGL) use a similar pattern.
Your machine does not know anything about class methods, they are normal functions under the hood.
Hence methods have to be implemented by always passing a pointer to the current object, it's just implicit in C++, i.e. T Class::method(...)
is just syntactic sugar for T Class_Method(Class* this, ...)
.
Other languages like Python or Lua choose to make it explicit and modern object-oriented C APIs like Vulkan (unlike OpenGL) use a similar pattern.
answered yesterday
Trass3r
2,7421429
2,7421429
add a comment |
add a comment |
up vote
2
down vote
"this" can also safeguard against shadowing by a function parameter, for example:
class Vector {
public:
double x,y,z;
void SetLocation(double x, double y, double z);
};
void Vector::SetLocation(double x, double y, double z) {
this->x = x; //Passed parameter assigned to member variable
this->y = y;
this->z = z;
}
(Obviously, writing such code is discouraged.)
Usually shadowing comes up as an issue when the member variable is being shadowed by an introduced local variable (where you normally aren't thinking of what is in the global scope), so use of this->x is encouraged to prevent such modification bugs.
– Tezra
15 hours ago
Yeah unfortunately -Wshadow is not enabled with -Wall. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
– Trass3r
6 hours ago
add a comment |
up vote
2
down vote
"this" can also safeguard against shadowing by a function parameter, for example:
class Vector {
public:
double x,y,z;
void SetLocation(double x, double y, double z);
};
void Vector::SetLocation(double x, double y, double z) {
this->x = x; //Passed parameter assigned to member variable
this->y = y;
this->z = z;
}
(Obviously, writing such code is discouraged.)
Usually shadowing comes up as an issue when the member variable is being shadowed by an introduced local variable (where you normally aren't thinking of what is in the global scope), so use of this->x is encouraged to prevent such modification bugs.
– Tezra
15 hours ago
Yeah unfortunately -Wshadow is not enabled with -Wall. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
– Trass3r
6 hours ago
add a comment |
up vote
2
down vote
up vote
2
down vote
"this" can also safeguard against shadowing by a function parameter, for example:
class Vector {
public:
double x,y,z;
void SetLocation(double x, double y, double z);
};
void Vector::SetLocation(double x, double y, double z) {
this->x = x; //Passed parameter assigned to member variable
this->y = y;
this->z = z;
}
(Obviously, writing such code is discouraged.)
"this" can also safeguard against shadowing by a function parameter, for example:
class Vector {
public:
double x,y,z;
void SetLocation(double x, double y, double z);
};
void Vector::SetLocation(double x, double y, double z) {
this->x = x; //Passed parameter assigned to member variable
this->y = y;
this->z = z;
}
(Obviously, writing such code is discouraged.)
answered 17 hours ago
Szak1
37539
37539
Usually shadowing comes up as an issue when the member variable is being shadowed by an introduced local variable (where you normally aren't thinking of what is in the global scope), so use of this->x is encouraged to prevent such modification bugs.
– Tezra
15 hours ago
Yeah unfortunately -Wshadow is not enabled with -Wall. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
– Trass3r
6 hours ago
add a comment |
Usually shadowing comes up as an issue when the member variable is being shadowed by an introduced local variable (where you normally aren't thinking of what is in the global scope), so use of this->x is encouraged to prevent such modification bugs.
– Tezra
15 hours ago
Yeah unfortunately -Wshadow is not enabled with -Wall. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
– Trass3r
6 hours ago
Usually shadowing comes up as an issue when the member variable is being shadowed by an introduced local variable (where you normally aren't thinking of what is in the global scope), so use of this->x is encouraged to prevent such modification bugs.
– Tezra
15 hours ago
Usually shadowing comes up as an issue when the member variable is being shadowed by an introduced local variable (where you normally aren't thinking of what is in the global scope), so use of this->x is encouraged to prevent such modification bugs.
– Tezra
15 hours ago
Yeah unfortunately -Wshadow is not enabled with -Wall. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
– Trass3r
6 hours ago
Yeah unfortunately -Wshadow is not enabled with -Wall. gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
– Trass3r
6 hours ago
add a comment |
up vote
2
down vote
if the compiler inlines a member function that is called with static rather than dynamic binding, it might be able to optimize away the this
pointer. Take this simple example:
#include <iostream>
using std::cout;
using std::endl;
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int main(void)
{
example e;
e.foo(10);
cout << e.foo() << endl;
}
GCC 7.3.0 with the -march=x86-64 -O -S
flag is able to compile cout << e.foo()
to three instructions:
movl $10, %esi
leaq _ZSt4cout(%rip), %rdi
call _ZNSolsEi@PLT
This is a call to std::ostream::operator<<
. Remember that cout << e.foo();
is syntactic sugar for std::ostream::operator<< (cout, e.foo());
. And operator<<(int)
could be written two ways: static operator<< (ostream&, int)
, as a non-member function, where the operand on the left is an explicit parameter, or operator<<(int)
, as a member function, where it’s implicitly this
.
The compiler was able to deduce that e.foo()
will always be the constant 10
. Since the 64-bit x86 calling convention is to pass function arguments in registers, that compiles down to the single movl
instruction, which sets the second function parameter to 10
. The leaq
instruction sets the first argument (which might be an explicit ostream&
or the implicit this
) to &cout
. Then the program makes a call
to the function.
In more complex cases, though—such as if you have a function taking an example&
as a parameter—the compiler needs to look up this
, as this
is what tells the program which instance it’s working with, and therefore, which instance’s x
data member to look up.
Consider this example:
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int bar( const example& e )
{
return e.foo();
}
The function bar()
gets compiled to a bit of boilerplate and the instruction:
movl (%rdi), %eax
ret
You remember from the previous example that %rdi
on x86-64 is the first function argument, the implicit this
pointer for the call to e.foo()
. Putting it in parentheses, (%rdi)
, means look up the variable at that location. (Since the only data in an example
instance is x
, &e.x
happens to be the same as &e
in this case.) Moving the contents to %eax
sets the return value.
In this case, the compiler needed the implicit this
argument to foo(/* example* this */)
to be able to find &e
and therefore &e.x
. In fact, inside a member function (that isn’t static
), x
, this->x
and (*this).x
all mean the same thing.
add a comment |
up vote
2
down vote
if the compiler inlines a member function that is called with static rather than dynamic binding, it might be able to optimize away the this
pointer. Take this simple example:
#include <iostream>
using std::cout;
using std::endl;
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int main(void)
{
example e;
e.foo(10);
cout << e.foo() << endl;
}
GCC 7.3.0 with the -march=x86-64 -O -S
flag is able to compile cout << e.foo()
to three instructions:
movl $10, %esi
leaq _ZSt4cout(%rip), %rdi
call _ZNSolsEi@PLT
This is a call to std::ostream::operator<<
. Remember that cout << e.foo();
is syntactic sugar for std::ostream::operator<< (cout, e.foo());
. And operator<<(int)
could be written two ways: static operator<< (ostream&, int)
, as a non-member function, where the operand on the left is an explicit parameter, or operator<<(int)
, as a member function, where it’s implicitly this
.
The compiler was able to deduce that e.foo()
will always be the constant 10
. Since the 64-bit x86 calling convention is to pass function arguments in registers, that compiles down to the single movl
instruction, which sets the second function parameter to 10
. The leaq
instruction sets the first argument (which might be an explicit ostream&
or the implicit this
) to &cout
. Then the program makes a call
to the function.
In more complex cases, though—such as if you have a function taking an example&
as a parameter—the compiler needs to look up this
, as this
is what tells the program which instance it’s working with, and therefore, which instance’s x
data member to look up.
Consider this example:
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int bar( const example& e )
{
return e.foo();
}
The function bar()
gets compiled to a bit of boilerplate and the instruction:
movl (%rdi), %eax
ret
You remember from the previous example that %rdi
on x86-64 is the first function argument, the implicit this
pointer for the call to e.foo()
. Putting it in parentheses, (%rdi)
, means look up the variable at that location. (Since the only data in an example
instance is x
, &e.x
happens to be the same as &e
in this case.) Moving the contents to %eax
sets the return value.
In this case, the compiler needed the implicit this
argument to foo(/* example* this */)
to be able to find &e
and therefore &e.x
. In fact, inside a member function (that isn’t static
), x
, this->x
and (*this).x
all mean the same thing.
add a comment |
up vote
2
down vote
up vote
2
down vote
if the compiler inlines a member function that is called with static rather than dynamic binding, it might be able to optimize away the this
pointer. Take this simple example:
#include <iostream>
using std::cout;
using std::endl;
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int main(void)
{
example e;
e.foo(10);
cout << e.foo() << endl;
}
GCC 7.3.0 with the -march=x86-64 -O -S
flag is able to compile cout << e.foo()
to three instructions:
movl $10, %esi
leaq _ZSt4cout(%rip), %rdi
call _ZNSolsEi@PLT
This is a call to std::ostream::operator<<
. Remember that cout << e.foo();
is syntactic sugar for std::ostream::operator<< (cout, e.foo());
. And operator<<(int)
could be written two ways: static operator<< (ostream&, int)
, as a non-member function, where the operand on the left is an explicit parameter, or operator<<(int)
, as a member function, where it’s implicitly this
.
The compiler was able to deduce that e.foo()
will always be the constant 10
. Since the 64-bit x86 calling convention is to pass function arguments in registers, that compiles down to the single movl
instruction, which sets the second function parameter to 10
. The leaq
instruction sets the first argument (which might be an explicit ostream&
or the implicit this
) to &cout
. Then the program makes a call
to the function.
In more complex cases, though—such as if you have a function taking an example&
as a parameter—the compiler needs to look up this
, as this
is what tells the program which instance it’s working with, and therefore, which instance’s x
data member to look up.
Consider this example:
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int bar( const example& e )
{
return e.foo();
}
The function bar()
gets compiled to a bit of boilerplate and the instruction:
movl (%rdi), %eax
ret
You remember from the previous example that %rdi
on x86-64 is the first function argument, the implicit this
pointer for the call to e.foo()
. Putting it in parentheses, (%rdi)
, means look up the variable at that location. (Since the only data in an example
instance is x
, &e.x
happens to be the same as &e
in this case.) Moving the contents to %eax
sets the return value.
In this case, the compiler needed the implicit this
argument to foo(/* example* this */)
to be able to find &e
and therefore &e.x
. In fact, inside a member function (that isn’t static
), x
, this->x
and (*this).x
all mean the same thing.
if the compiler inlines a member function that is called with static rather than dynamic binding, it might be able to optimize away the this
pointer. Take this simple example:
#include <iostream>
using std::cout;
using std::endl;
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int main(void)
{
example e;
e.foo(10);
cout << e.foo() << endl;
}
GCC 7.3.0 with the -march=x86-64 -O -S
flag is able to compile cout << e.foo()
to three instructions:
movl $10, %esi
leaq _ZSt4cout(%rip), %rdi
call _ZNSolsEi@PLT
This is a call to std::ostream::operator<<
. Remember that cout << e.foo();
is syntactic sugar for std::ostream::operator<< (cout, e.foo());
. And operator<<(int)
could be written two ways: static operator<< (ostream&, int)
, as a non-member function, where the operand on the left is an explicit parameter, or operator<<(int)
, as a member function, where it’s implicitly this
.
The compiler was able to deduce that e.foo()
will always be the constant 10
. Since the 64-bit x86 calling convention is to pass function arguments in registers, that compiles down to the single movl
instruction, which sets the second function parameter to 10
. The leaq
instruction sets the first argument (which might be an explicit ostream&
or the implicit this
) to &cout
. Then the program makes a call
to the function.
In more complex cases, though—such as if you have a function taking an example&
as a parameter—the compiler needs to look up this
, as this
is what tells the program which instance it’s working with, and therefore, which instance’s x
data member to look up.
Consider this example:
class example {
public:
int foo() const { return x; }
int foo(const int i) { return (x = i); }
private:
int x;
};
int bar( const example& e )
{
return e.foo();
}
The function bar()
gets compiled to a bit of boilerplate and the instruction:
movl (%rdi), %eax
ret
You remember from the previous example that %rdi
on x86-64 is the first function argument, the implicit this
pointer for the call to e.foo()
. Putting it in parentheses, (%rdi)
, means look up the variable at that location. (Since the only data in an example
instance is x
, &e.x
happens to be the same as &e
in this case.) Moving the contents to %eax
sets the return value.
In this case, the compiler needed the implicit this
argument to foo(/* example* this */)
to be able to find &e
and therefore &e.x
. In fact, inside a member function (that isn’t static
), x
, this->x
and (*this).x
all mean the same thing.
edited 7 hours ago
answered yesterday
Davislor
8,22111126
8,22111126
add a comment |
add a comment |
up vote
1
down vote
this
is a pointer. It's like an implicit parameter that's part of every method. You could imagine using plain C functions and writing code like:
Socket makeSocket(int port) { ... }
void send(Socket *this, Value v) { ... }
Value receive(Socket *this) { ... }
Socket *mySocket = makeSocket(1234);
send(mySocket, someValue); // The subject, `mySocket`, is passed in as a param called "this", explicitly
Value newData = receive(socket);
In C++, similar code might look like:
mySocket.send(someValue); // The subject, `mySocket`, is passed in as a param called "this"
Value newData = mySocket.receive();
add a comment |
up vote
1
down vote
this
is a pointer. It's like an implicit parameter that's part of every method. You could imagine using plain C functions and writing code like:
Socket makeSocket(int port) { ... }
void send(Socket *this, Value v) { ... }
Value receive(Socket *this) { ... }
Socket *mySocket = makeSocket(1234);
send(mySocket, someValue); // The subject, `mySocket`, is passed in as a param called "this", explicitly
Value newData = receive(socket);
In C++, similar code might look like:
mySocket.send(someValue); // The subject, `mySocket`, is passed in as a param called "this"
Value newData = mySocket.receive();
add a comment |
up vote
1
down vote
up vote
1
down vote
this
is a pointer. It's like an implicit parameter that's part of every method. You could imagine using plain C functions and writing code like:
Socket makeSocket(int port) { ... }
void send(Socket *this, Value v) { ... }
Value receive(Socket *this) { ... }
Socket *mySocket = makeSocket(1234);
send(mySocket, someValue); // The subject, `mySocket`, is passed in as a param called "this", explicitly
Value newData = receive(socket);
In C++, similar code might look like:
mySocket.send(someValue); // The subject, `mySocket`, is passed in as a param called "this"
Value newData = mySocket.receive();
this
is a pointer. It's like an implicit parameter that's part of every method. You could imagine using plain C functions and writing code like:
Socket makeSocket(int port) { ... }
void send(Socket *this, Value v) { ... }
Value receive(Socket *this) { ... }
Socket *mySocket = makeSocket(1234);
send(mySocket, someValue); // The subject, `mySocket`, is passed in as a param called "this", explicitly
Value newData = receive(socket);
In C++, similar code might look like:
mySocket.send(someValue); // The subject, `mySocket`, is passed in as a param called "this"
Value newData = mySocket.receive();
answered 6 hours ago
Alexander
30.1k44474
30.1k44474
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53264848%2fis-the-this-pointer-just-a-compile-time-thing%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
32
Both
x
andthis->x
access the member via the pointer to the object whose member it is. How else could they possibly work? Being able to writex
is merely syntactic sugar, a convenient shorthand.– Igor Tandetnik
yesterday
7
" since i usually use it every single time i refer to a member variable or function" - why? It's almost always unnecessary to do this.
– Neil Butterworth
yesterday
7
@NeilButterworth because if you have a big class with numerous methods and members and if the methods are equally broad it is nice to immediately see where this function or variable might come from. Also it is just my style of coding which i prefer and now i wanted to know if it could have an impact on something.
– Yastanub
yesterday
4
Would it help you to think in these terms?: “When you type
x = X;
the compiler automatically replaces it withthis->x = X;
”. It still glosses over details, but it’s not a bad mental model to explain why the two versions are the same.– Euro Micelli
yesterday
4
Possible duplicate of Is there overhead using this-> in c++?
– underscore_d
yesterday