I know this is silly and the title probably isn't the answer..
I always thought of this as a pointer to the current object which is supplied in every method call from an object (which is not a static method)
but looking at what my code actually returns for example:
Test& Test::func ()
{
// Some processing
return *this;
}
the dereference of this is returned... and the return type is a reference to the object.... so what does that make this? Is there something under the hood I'm not understanding well?
Remember that a reference is simply a different name for an object.
That implies that returning a reference is the same thing as returning an object on type level of abstraction; it is not the same thing in the result: returning a reference means the caller gets a reference to the current object, whereas returning an object gives him (a reference to) a copy of the current object - with all the consequences, like the copy constructor being called, deep copy decisions are being made, etc.
From cppreference:
The keyword this is a prvalue expression whose value is the address of the object, on which the member function is being called.
And then (perhaps easier to grasp):
The type of this in a member function of class X is X* (pointer to X). If the member function is cv-qualified, the type of this is cv X* (pointer to identically cv-qualified X). Since constructors and destructors cannot be cv-qualified, the type of this in them is always X*, even when constructing or destroying a const object.
So, this is not a pointer to a reference, but just a pointer.
Actually you cannot have a pointer to a reference, because taking the address of a reference will give you the address of referenced object.
Further, there is no special syntax in C++ to form a reference. Instead references have to be bound on initialization, for example:
int x = 3;
int& y = x; // x is int, but y is int&
assert( &y == &x); // address of y is the address of x
Similar when returning a reference from a function:
int& get_x() {
static int x = 3;
return x;
}
To put it simply:
test t1; // t1 is a test object.
test& t2 = t1; // t2 is another name for t1.
test* t3; // t3 holds an address of a test object.
*t3; // derefernce t. which gives you, the test object that t3 points to.
this is a pointer to the current test object.
therefore *this is the current test object, and because the return value type is test&, when you call the function, you get the same object you called the function from.
Related
I'm learning C++ and pointers and I thought I understood pointers until I saw this.
On one side the asterix(*) operator is dereferecing, which means it returns the value in the address the value is pointing to, and that the ampersand (&) operator is the opposite, and returns the address of where the value is stored in memory.
Reading now about assignment overloading, it says "we return *this because we want to return a reference to the object". Though from what I read *this actually returns the value of this, and actually &this logically should be returned if we want to return a reference to the object.
How does this add up? I guess I'm missing something here because I didn't find this question asked elsewhere, but the explanation seems like the complete opposite of what should be, regarding the logic of * to dereference, & get a reference.
For example here:
struct A {
A& operator=(const A&) {
cout << "A::operator=(const A&)" << endl;
return *this;
}
};
this is a pointer that keeps the address of the current object. So dereferencing the pointer like *this you will get the lvalue of the current object itself. And the return type of the copy assignment operator of the presented class is A&. So returning the expression *this you are returning a reference to the current object.
According to the C++ 17 Standard (8.1.2 This)
1 The keyword this names a pointer to the object for which a
non-static member function (12.2.2.1) is invoked or a non-static data
member’s initializer (12.2) is evaluated.
Consider the following code snippet as an simplified example.
int x = 10;
int *this_x = &x;
Now to return a reference to the object you need to use the expression *this_x as for example
std::cout << *this_x << '\n';
& has multiple meanings depending on the context. In C and used alone, I can either be a bitwise AND operator or the address of something referenced by a symbol.
In C++, after a type name, it also means that what follows is a reference to an object of this type.
This means that is you enter :
int a = 0;
int & b = a;
… b will become de facto an alias of a.
In your example, operator= is made to return an object of type A (not a pointer onto it). This will be seen this way by uppers functions, but what will actually be returned is an existing object, more specifically the instance of the class of which this member function has been called.
Yes, *this is (the value of?) the current object. But the pointer to the current object is this, not &this.
&this, if it was legal, would be a pointer-to-pointer to the current object. But it's illegal, since this (the pointer itself) is a temporary object, and you can't take addresses of those with &.
It would make more sense to ask why we don't do return this;.
The answer is: forming a pointer requires &, but forming a reference doesn't. Compare:
int x = 42;
int *ptr = &x;
int &ref = x;
So, similarly:
int *f1() return {return &x;}
int &f1() return {return x;}
A simple mnemonic you can use is that the * and & operators match the type syntax of the thing you're converting from, not the thing you're converting to:
* converts a foo* to a foo&
& converts a foo& to a foo*
In expressions, there's no meaningful difference between foo and foo&, so I could have said that * converts foo* to foo, but the version above is easier to remember.
C++ inherited its type syntax from C, and C type syntax named types after the expression syntax for using them, not the syntax for creating them. Arrays are written foo x[...] because you use them by accessing an element, and pointers are written foo *x because you use them by dereferencing them. Pointers to arrays are written foo (*x)[...] because you use them by dereferencing them and then accessing an element, while arrays of pointers are written foo *x[...] because you use them by accessing an element and then dereferencing it. People don't like the syntax, but it's consistent.
References were added later, and break the consistency, because there isn't any syntax for using a reference that differs from using the referenced object "directly". As a result, you shouldn't try to make sense of the type syntax for references. It just is.
The reason this is a pointer is also purely historical: this was added to C++ before references were. But since it is a pointer, and you need a reference, you have to use * to get rid of the *.
Can someone tell me if this is safe, because I think it isn't:
class A
{
public:
A(int*& i) : m_i(i)
{}
int*& m_i;
};
class B
{
public:
B(int* const& i) : m_i(i)
{}
int* const & m_i;
};
int main()
{
int i = 1;
int *j = &i;
A a1(j); // this works (1)
A a2(&i); // compiler error (2)
B b(&i); // this works again (3)
}
I understand why (1) works. We are passing a pointer, the function accepts it as a reference.
But why doesn't (2) work? From my perspective, we are passing the same pointer, just without assigning it to a pointer variable first. My guess is that &i is an rvalue and has no memory of its own, so the reference cannot be valid. I can accept that explanation (if it's true).
But why the heck does (3) compile? Wouldn't that mean that we allow the invalid reference so b.m_i is essentially undefined?
Am I completely wrong in how this works? I am asking because I am getting weird unit test fails that I can only explain by pointers becoming invalid. They only happen for some compilers, so I was assuming this must be something outside the standard.
So my core question basically is: Is using int* const & in a function argument inherently dangerous and should be avoided, since an unsuspecting caller might always call it with &i like with a regular pointer argument?
Addendum: As #franji1 pointed out, the following is an interesting thought to understand what happens here. I modified main() to change the inner pointer and then print the members m_i:
int main()
{
int i = 1;
int *j = &i; // j points to 1
A a1(j);
B b(&i);
int re = 2;
j = &re; // j now points to 2
std::cout << *a1.m_i << "\n"; // output: 2
std::cout << *b.m_i << "\n"; // output: 1
}
So, clearly a1 works as intended.
However, since b cannot know that j has been modified, it seems to hold a reference to a "personal" pointer, but my worry is that it is not well defined in the standard, so there might be compilers for which this "personal" pointer is undefined. Can anyone confirm this?
A's constructor takes a non-const reference to an int* pointer. A a1(j); works, because j is an int* variable, so the reference is satisfied. And j outlives a1, so the A::m_i member is safe to use for the lifetime of a1.
A a2(&i); fails to compile, because although &i is an int*, operator& returns a temporary value, which cannot be bound to a non-const reference.
B b(&i); compiles, because B's constructor takes a reference to a const int*, which can be bound to a temporary. The temporary's lifetime will be extended by being bound to the constructor's i parameter, but will then expire once the constructor exits, thus the B::m_i member will be a dangling reference and not be safe to use at all after the constructor has exited.
j is an lvalue and as such it can be bound to a non-const lvaue reference.
&i is a prvalue and it cannot be bound to non-const lvalue reference. That's why (2) doesn't compile
&i is a prvalue (a temporary) and it can be bound to a const lvalue reference. Bounding a prvalue to a reference extends the lifetime of the temporary to the lifetime of the reference. In this case this temporary lifetime is extended to the lifetime of the constructor parameter i. You then initialize the reference m_i to i (constructor parameter) (which is a reference to the temporary) but because i is an lvalue the lifetime of the temporary is not extended. In the end you end up with a reference member m_i bound to an object which is not alive. You have a dangling reference. Accessing m_i from now on (after the constructor has finished) is Undefined Behavior.
Simple table of what can references bind to: C++11 rvalue reference vs const reference
Pointer is a memory address. For simplicity, think of a pointer as uint64_t variable holding a number representing the memory address of whatever. Reference is just a alias for some variable.
In example (1) you are passing a pointer to constructor expecting a reference to pointer. It works as intended, as compiler gets the address of memory where the value of pointer is stored and passes it to constructor. The constructor gets that number and creates an alias pointer. As a result you are getting an alias of j. If you modify j to point to something else then m_i will also be modified. You can modify m_i to point to something else too.
In example (2) you are passing a number value to the constructor expecting a reference to pointer. So, instead of an address of an address, constructor gets an address and compiler has no way to satisfy the signature of the constructor.
In example (3) you are passing a number value to constructor expecting a constant reference to pointer. Constant reference is a fixed number, just a memory address. In this case compiler understands the intent and provides the memory address to set in the constructor. As a result you are getting fixed alias of i.
EDIT (for clarity): Difference between (2) and (3) is that &i is not a valid reference to int*, but it is a valid const reference to int*.
this is a const ptr to the object/instance which a member function receive implicitly, so how does return *this returns a reference ?
As of what I know , a pointer dereferencing to a variable means it holds it's memory address , so return *this should return value dereferenced by this const pointer which is what? An object?
Also, why you can't do something like this:
Calc cCalc;
cCalc.Add(5).Sub(3).Mult(4);
Without having all that member functions to return *this?
I would want to know how pointers and reference treat objects/instances.
Let's try to untangle:
this is a const ptr to the object/instance which a member function receive implicitly
member functions indeed receive this pointer implicitly. The type is T* or const T* depending on the member function signature -- you get const placing const keyword at the tail after the ().
so how does return *this returns a reference ?
*this dereference the pointer, thus creating lvalue of type T or const T respectively. If your question is meant how you get T& from *this in a const funstion, the answer that you don't, that attempt would be ill-formed code.
As of what I know , a pointer dereferencing to a variable means it holds it's memory address , so return *this should return value dereferenced by this const pointer which is what? An object?
*this denotes the instance. And it is lvalue expression. So you can get its address agan (providing same as this), or can bind it to a reference -- including the case for a return.
The chaining you show can actually be done if the functions returned Calc instead of Calc& or returned some different object than *this -- but then the result of calculations would end up in that place. Not where you expect it: in cCalc.
As it stands, when all three functions return *this leads first Add taking &cCalc in this, and returns cCalc. The next call to Sub has the same situation. And Multiply too.
Add member doesnt have Sub function. Compiler give an error.
But, if you return *this, you are returning your own object (not reference). Now you have one cCalc object that can use Sub(3). Sub(3) return your object and can use Mult(4).
There seems to be many relavent questions talking about pointer vs. reference, but I couldn't find what I want to know. Basically, an object is passed in by a reference:
funcA(MyObject &objRef) { ... }
Within the function, can I get a pointer to that object instead of the reference? If I treat the reference objRef as an alias to the MyObject, would &objRef actually give me a pointer to the MyObject? It doesn't seem likely. I am confused.
Edit: Upon closer examination, objRef does give me back the pointer to object that I need - Most of you gave me correct info/answer, many thanks. I went along the answer that seems to be most illustrative in this case.
Yes, applying the address-of operator to the reference is the same as taking the address of the original object.
#include <iostream>
struct foo {};
void bar( const foo& obj )
{
std::cout << &obj << std::endl;
}
int main()
{
foo obj;
std::cout << &obj << std::endl;
bar( obj );
return 0;
}
Result:
0x22ff1f
0x22ff1f
Any operator applied to a reference will actually apply to the object it refers to (§5/5 [expr]); the reference can be thought of as another name for the same object. Taking the address of a reference will therefore give you the address of the object that it refers to.
It as actually unspecified whether or not a reference requires storage (§8.3.2/4 [dcl.ref]) and so it wouldn't make sense to take the address of the reference itself.
As an example:
int x = 5;
int& y = x;
int* xp = &x;
int* yp = &y;
In the above example, xp and yp are equal - that is, the expression xp == yp evaluates to true because they both point to the same object.
The general solution is to use std::addressof, as in:
#include <type_traits>
void foo(T & x)
{
T * p = std::addressof(x);
}
This works no matter whether T overloads operator& or not.
Use the address operator on the reference.
MyObject *ptr = &objRef;
Use the address-of (&) operator on the reference.
&objRef
Like any other operator used on a reference, this actually affects the referred-to object.
As #Kerrek points out, since the operator affects the referred-to object, if that object has an overloaded operator& function, this will call it instead and std::address_of is needed to get the true address.
In C++, a reference is a restricted type of pointer. It can only be assigned once and can never have a NULL value.
References are most useful when used to indicate that a parameter to a function is being Passed by Reference where the address of the variable is passed in. Without a Reference, Pass By Value is used instead.
after doing some test-code for this link :
Is it safe to call temporary object's methods?
I found a rather strange feature of the c++ language, which I'm not sure how it works :
struct Test{
int i;
Test(int ii):i(ii){}
Test& operator=(int ii){
i = ii;
return *this;
}
Test operator+(const Test& rhs){
return Test(i + rhs.i);
}
void non_const_function(){
i *= i;
}
};
int main(){
//code below gives errors, builtin types don't allow evil code
//int i = 5+5 = 8;
//int& iRef = 5+5;
//int* iPtr = &(5+5);
//5 = 10;
Test x = Test(5) + Test(5) = 8;//assign to a temporary
Test& xRef = Test(5) + Test(5);//reference to a temporary
Test* xPtr = &(Test(5) + Test(5));//address of a temporary
Test(5) = Test(10);//assign to a temporary
Test(8).non_const_function();//call a non-const function
return 0;
}
xRef and xPtr are both working pointers, with the expected values.
Of course I wouldn't write such code in a real project, but I'm still interested how / why this works.
The only info I found on google about this was that "if you create a reference to a temporary, the temporaries lifetime is linked to the lifetime of the reference"
Note :
-not all compilers are that forgiving, e.g. Metrowerks ARM (does it use GCC ?) only allows const reference to temporaries.
EDIT :
-increasing the warning to W4 in VC++ 2008 showed lots of errors - good to know.
EDIT 2:
Thank you all for the help. I'm back to work, fixing 100's of warnings.
CONCLUSION : use highest warning from start (I even found a REAL bug thanks to /G4)
Let's go line by line:
Test x = Test(5) + Test(5) = 8;//assign to a temporary
There's no big deal here. Temporaries are still just normal objects, and thus the assignment operator works on them just as it would on anything else.
Test& xRef = Test(5) + Test(5);//reference to a temporary
Like Metroworks, my GCC doesn't allow a non-const reference to a temporary.
Test* xPtr = &(Test(5) + Test(5));//address of a temporary
In addition, GCC warns about taking the address of a temporary, for obvious reasons.
Test(5) = Test(10);//assign to a temporary
Again, this is just assignment, which, as I explained above, is no big deal.
Test(8).non_const_function();//call a non-const function
Temporary objects aren't constant. There's nothing stopping them from calling non-const functions.
This kind of thing is ubiquitous in many object-oriented programming languages, especially those with object overloading.
If the first statement were written
Text x = Test(5).add(Test(5)).set(8);
where .add and .set return the lefthand Test instances with the expected values, would you still be confused?
To break this example down, you're creating a Test object with value 5, then adding another Test object with value 5 to it, and returning the first Test object, now with value 10. Then you're setting its value to 8, and assigning that object to x (well actually it's not assignment, again you're creating a Test object named x, then setting its value to the temporary's value).
Regarding the first case, assigning to a temporary, I recall from my Effective C++ that it is good practice to declare your operators like
const Test operator+(const Test&) const
This will make the objects behave like built-in types in that respect, at least.
The assignment operator is just a function with a funny name. If you can call a function on a temporary (which you can), then you can assign to a temporary, given a suitable operator=().
My reading of your question tells me you are confused with the lifetime of temporaries more than anything else. I think it will help if you put a couple of couts as below:
struct Test{
int i;
Test(int ii):i(ii){ std::cout << "new object\n"; }
Test& operator=(int ii){
i = ii;
return *this;
}
Test operator+(const Test& rhs){
return Test(i + rhs.i);
}
void non_const_function(){
i *= i;
}
~Test() { std::cout << "deleting ...\n"; }
};
Now run, and you should be able to see what exactly is going on under the hoods. (Style Check:Not checking for self-assignment is not a good thing.)
It will also help if you refer the standard: It discusses something similar to what you have posted:
12.2 Temporary objects
4 There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when a default constructor is called to initialize an element of an array. If the constructor has one or more default arguments, the destruction of every temporary created in a default argument expression is sequenced before the construction of the next array element, if any.
5 The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call. A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits. A temporary bound to a reference in a new-initializer (5.3.4) persists until the completion of the
full-expression containing the new-initializer.
struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };
S* p = new S{ 1, {2,3} }; // Creates dangling reference
[ Note: This may introduce a dangling reference, and implementations are encouraged to
issue a warning in such a case. —end note ] The destruction of a temporary whose lifetime is not extended by being bound to a reference is sequenced before the destruction of every temporary which is constructed earlier in the same full-expression. If the lifetime of two or more temporaries to which references are bound ends at the same point, these temporaries are destroyed at that point in the reverse order of the completion of their construction. In addition, the destruction of temporaries bound to references shall take into account the ordering of destruction of objects with static, thread, or automatic storage duration (3.7.1, 3.7.2, 3.7.3); that is, if obj1 is an object with the same storage duration as the temporary and created before the temporary is created the temporary shall be destroyed before obj1 is destroyed; if obj2 is an object with the same storage duration as the temporary and created after the temporary is created the temporary shall be destroyed after obj2 is destroyed. Example:
struct S {
S();
S(int);
friend S operator+(const S&, const S&);
~S();
};
S obj1;
const S& cr = S(16)+S(23);
S obj2;
the expression C(16)+C(23) creates three temporaries. A first temporary T1 to hold the result of the expression C(16), a second temporary T2 to hold the result of the expression C(23), and a third temporary T3 to hold the result of the addition of these two expressions. The temporary T3 is then bound to the reference cr. It is unspecified whether T1 or T2 is created first. On an implementation where T1 is created before T2, it is guaranteed that T2 is destroyed before T1. The temporaries T1 and T2 are bound to the reference parameters of operator+; these temporaries are destroyed at the end of the full-expression containing the call to operator+. The temporary T3 bound to the reference cr is destroyed at the end of cr’s lifetime,
that is, at the end of the program. In addition, the order in which T3 is destroyed takes into account the destruction order of other objects with static storage duration. That is, because obj1 is constructed before T3, and T3 is constructed before obj2, it is guaranteed that obj2 is destroyed before T3, and that T3 is destroyed before obj1.
Take a look at the GotW #4 which discusses the mechanics creating a user-defined class that most closely mirrors built-in arithmetic types. If you take his advice, your Test struct would look more like this:
struct Test{
...
Test& operator+=( const Test& other ) {
i += other.i;
return *this;
}
...
};
const Test operator+( const Test& lhs, const Test& rhs ) {
Test ret( lhs );
ret += rhs;
return ret;
}
Now Test behaves much better in the addition situations (lines 1, 2, and 3 fail to compile). This is one of the rare instances where returning a const copy is actually useful,