Meaning of reference in assignment - c++

why is it possible to change the value of the constant z in the C++ snippet below? What is the meaning of (int&) in the 5th line? Note that the addresses of x, y, z are different (cout << &x << &y << &z). Thank you very much!
int x = 2;
int y = 3;
const int z = x;
cout << z; // the result is 2
(int&) z = y;
cout << z; // the result is 3

Because in this case we have a cast on the left side of an assignment expression that tells to compiler we are forcing our identifier in order it behaves as a not read-only reference to its memory location, and since we are knowingly "forcing" a behaviour, compiler trust us and allows this assignment.
In some cases this is potentially dangerous, as when you assign the const identifier with a literal value, because it is not standard how compilers implement this initialization, in fact some compilers seems that replace the occurrences of identifiers with the literal values, as well as a macro expansion, so you have to pay a very close attention doing this operation.

Related

How is the following expression be executed?

What is the output of the following program?
#include <iostream>
using namespace std;
int main()
{
int a = 2, b = 4;
a++ = b;
cout << a << b;
return 0;
}
This is not legal C++ code.
The statement
a++ = b;
is not legal. Intuitively, you can only place something on the left-hand side of an assignment expression if it represents an object, not a value. For example, we can't write
x + y = z;
because x + y is a value, not an object. The same principle is at play in your code: the expression a++ is not something that can be written to, as it means "change a by adding one to it, then produce the value that a used to have."
The comments on your question talk about the formal terms that are used to describe what I'm referring to here as "values" and "something can be written to." These are formally called lvalues, rvalues, prvalues, etc., and it might be worth looking into these to learn more about what sorts of assignment statements are legal.

C++: What is a de-reference actually doing?

I am reading through Stroustrup's 4th edition : The C++ Programming Language. I have a python/java background so the first 4 chapters are fine so far.
In Chapter 3 I saw:
complex& operator+=(complex z) { re+=z.re , im+=z.im; return ∗this; }
That began a day long attempt to write this question:
First I figured out that it is returning a reference to the object and not a copy. As I was able to confirm in this question.
And I was able to understand the difference between returning a reference into a reference variable vs. a regular variable from this question
And I did my own trial
class Test {
public:
Test():x{5}{}
int x;
void setX(int a) {x = a;}
Test& operator+=(Test z) {x+=z.x; return *this;}
// the keyword this is a pointer
Test* getTest() {return this;}
// but I can return the reference by *this
Test& getTest1() {return *this;}
// or I can return a copy
Test getTest2() {return *this;}
};
That lead me to question why it is called de-reference, so I did this trial
int x = 8;
int* p = &x;
int y = *p;
int& z = *p;
x++; // let's have some fun
std::cout << y << std::endl;
std::cout << z << std::endl;
As expected y = 8 and z = 9, so how did the de-reference return the address in one case, and the value in the other? More importantly how is C++ making that distinction?
It's exactly like in your Test class functions.
int y = *p;
int& z = *p;
y is a copy of what p points to.
z is a reference to (not an address) what p points to. So changing z changes *p and vice-versa. But changing y has no effect on *p.
As expected y = 8 and z = 9, so how did the de-reference return the address in one case, and the value in the other? More importantly how is C++ making that distinction?
The de-reference returned the actual thing referenced in both cases. So there is no distinction for C++ to make. The difference is in what was done with the result of the dereference.
If you do int j = <something>; then the result of the something is used to initialize j. Since j is an integer, the <something> must be an integer value.
If you do int &j = <something>; then the result of the something is still used to initialize j. But now, j is a reference to an integer, and the <something> must be an integer, not just an integer value.
So, what *this does is the same in both cases. How you use a value doesn't affect how that value is computed. But how you use it does affect what happens when you use it. And these two pieces of code use the dereferenced object differently. In one case, its value is taken. In the other case, a reference is bound to it.
It's possible to consider a pointer int* p as pointing to an address where data of type int resides. When you de-reference this, the system retrieves the value at that memory address (the address is the actual value of p itself). In the case of int y = *p; you put a copy of that int value on the stack as the locator value y.
On the other hand, de-referencing on the left-hand side in *p = 13; means you are replacing the int value *p stored at the memory address denoted by the value of p with the right-hand-side value 13.
The reference lvalue int& z in int& z = *p; is not a copy of the int value pointed to by p but rather a left-hand side reference to whatever is at the particular memory address returned by *p (i.e. the actual value held by p itself).
This doesn't mean much difference in your contrived case, but e.g. given a Foo class with a Foo::incrementCount() value,
Foo* p = new Foo();
p->incrementCount();
Foo& ref = *p;
ref.incrementCount();
The same method for the same instance will be called twice. In contrast, Foo foo = *p will actually copy the entire Foo instance, creating a separate copy on the stack. Thus, calling foo.incrementValue() won't affect the separate object still pointed to by p.

C++ const pointers - Unexplained behaviour

I have this piece of code:
const int x = 7;
const int &y = x;
int *z = (int*)&y;
*z = 8;
cout << x<< endl;
cout << y<< endl;
cout << *z<< endl;
Which produces the following output:
7
8
8
I know that one should not remove the const as I did above. However, why does x print out 7? I've only created a single var, so if the output shows 7 and 8, then then there should be 2 vars created. How come there be 2 different numbers printed.
I know that one should not remove the const as I did above.
Right. Doing so is undefined behaviour, which means anything can happen. (More precisely, creating z is not undefined behaviour; modifying x through it is.)
However, why does x print out 7? I've only created a single var, so if the output shows 7 and 8, then then there should be 2 vars created. How come there be 2 different numbers printed.
Reasoning about undefined behaviour is weird - but it can be useful to understand what is happening for debugging purposes. It this case, what has almost certainly happened, is that the compiler has optimized:
cout << x<< endl;
to
cout << 7 << endl;
because there is no way you can legitimately modify the value of x. You then illegitimately modify the value of x, and manage to print out the new value.
Important Note
Do not attempt to rely on this behaviour; as I said above, it is only useful for debugging purposes. If the compiler changes it might get better at optimization and just print 7 for all values (because *z = 8 is undefined behaviour), or it might put x in read-only memory (and cause a access violation), or it might end up printing 8 for all values, or anything else might happen.
However, why does x print out 7?
Modifying a const object has undefined behaviour.
Casting away const-ness and using the pointer to modify a const object has undefined behavior. You are seeing the result of that.
The standard even has almost the same example you posted.
[dcl.type.cv/4]
Except that any class member declared mutable can be modified, any
attempt to modify a const object during its lifetime results in
undefined behavior. [ Example:
const int ci = 3; // cv-qualified (initialized as required)
ci = 4; // ill-formed: attempt to modify const
int i = 2; // not cv-qualified
const int* cip; // pointer to const int
cip = &i; // OK: cv-qualified access path to unqualified
*cip = 4; // ill-formed: attempt to modify through ptr to const
int* ip;
ip = const_cast<int*>(cip); // cast needed to convert const int* to int*
*ip = 4; // defined: *ip points to i, a non-const object
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
For another example,
struct X {
mutable int i;
int j;
};
struct Y {
X x;
Y();
};
const Y y;
y.x.i++; // well-formed: mutable member can be modified
y.x.j++; // ill-formed: const-qualified member modified
Y* p = const_cast<Y*>(&y); // cast away const-ness of y
p->x.i = 99; // well-formed: mutable member can be modified
p->x.j = 99; // undefined: modifies a const member
 — end example ]

Clarification of References in C++

So I am attempting to learn C++ and I have come across something that puzzles me slightly. I have the code,
int x = 0;
int &y = x;
cout << &x<< " " << x << " " << &y << " " <<y<< endl;
This compiles fine and results in:
0 003AFA08 0 003AFA08
What I have trouble understanding why the conversion of x, an int, to &y, a reference, doesn't result in an error. At first I thought it was some sort of conversion however,
int &y = &x;
results in an error.
Can anyone explain why this works in this way? Thanks in advance.
int& is not an address. It is a reference.
int& y = x; declares y as a reference to x. It effectively means that y becomes another name for x. Any time you use y, it is as if you had said x.
Pointers (not references) are used to store addresses. int& y = &x; is not valid because &x is the address of x (it's an int*). y is a reference to an int, not a reference to an int*.
It isn't a conversion. When you have a variable type of T & where T is some random type, you are basically saying "I'm declaring a name which is an alias for another name or possibly an anonymous value.". It's more like a typedef than a pointer.
References happen to often be implemented as addresses, but that isn't a good model for thinking about what they are.
In your example that you're puzzled by:
int * const &y = &x;
would work just fine. Then y becomes an alias for the temporary result of taking the address of x. Notice that it is a reference to a pointer. It has to be a reference to a constant pointer because it is a reference to a temporary value.

Difference between function arguments declared with & and * in C++

I typed the following example:
#include <iostream>
double f(double* x, double* y)
{
std::cout << "val x: " << *x << "\n";
std::cout << "val y: " << *y << "\n";
return *x * *y;
}
double f2(double &x, double &y)
{
std::cout << "val x: " << x << "\n";
std::cout << "val y: " << y << "\n";
return x * y;
}
int main()
{
double a, b;
a = 2;
b = 3;
std::cout << f(&a, &b) << "\n";
std::cout << f2(a, b) << "\n";
return 0;
}
In the function f I declare x and y as pointers of which I can get the value by using *x. When calling f I need to pass the address of my passed arguments, that is why I pass &a, &b. f2 is the same except the definition is different.
Now my question is: Are they both really the same concerning memory management? Both not making any copy of the passed value but instead passing a reference?
I wonder about f2 because I couldn't read out the address of x in f2 so I know more about x and y in f (there I know address AND value).
Edit: After doing some more research, I found a quite useful topic:
Pointer vs. Reference
There's also a link to google coding guidelines http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments which is quite useful I feel (as I understood now, it's a form of subject taste) to make more clear
f2 is taking it's arguments by reference, which is essentially an alias for the arguments you pass. The difference between pointer and reference is that a reference cannot be NULL. With the f you need to pass the address (using & operator) of the parameters you're passing to the pointer, where when you pass by reference you just pass the parameters and the alias is created.
Passing by const reference (const double& ref) is preferred when you are not going to change the arguments inside the function, and when you are going to change them, use non-const reference.
Pointers are mostly used when you need to be able to pass NULL to your parameters, obviously you'd need to check then inside your function if the pointer was not NULL before using it.
This is just syntactic sugar to avoid having to use * everytime you reference the argument. You still can use & to have the address of x in f2.
In my head, parameters of functions are always passed by value. Passing an int is easy to imagine, passing a double is just bigger and passing a struct or class could be very big indeed.
But passing a pointer to something, well, you're just passing an address by value. (A pointer is often a convenient size for the CPU just like an int.)
A reference is very similar, and certainly I think of a reference as a pointer, but with syntactic sugar to make it look like the object its referring to has been passed by value.
You can also think of a reference as a const pointer, ie:
int i;
int j;
int* p = &i; // pointer to i
int* const cp = p; // cp points to i, but cp cannot be modified
p = &j; // OK - p is modified to point to j
*cp = 0; // OK - i is overwritten
cp = &j; // ERROR - cp cannot be modified
int& ri = i; // ri refers to i
ri = 1; // i is overwritten
ri = j; // i is overwritten again
// Did you think ri might refer to j?
So, a pointer does double time: It is a value in its own right, but it can also point to another value when you dereference it, eg: *p.
Also, having reference parameters means that you cannot make them refer to anything else during the lifetime of the function because there's no way to express that.
A reference is supposed not to be able to be initialised with null, but consider this:
void foo(int& i);
int* p = 0;
foo(*p);
This means that pointers should be checked before you use them, but references cannot be checked. The implementation of foo() could try to read from or write to i which will cause an access violation.
In the above example the pointer p should have been checked before being used in the call to foo:
if (p) foo(*p);
Another difference that hasn't been mentioned is that you cannot change what a reference refers to. This doesn't make a lot of difference in the function call example shown in the original question.
int X(10), Y(20);
int *pX = X;
int& rY = Y;
*pX = 15; // change value of X
rY = 25; // change value of Y
pX = Y; // pX now points to Y
rY always points to Y and cannot be moved.
References can't be used to index into simple arrays like pointers.
You should have been able to read x address in both functions.
To do so in f2, you must of course prefix x by a & since there, x is a reference to a double, and you want an address.
A worth noticing difference between references and pointers is that the former cannot be NULL. You must pass something (valid) while when providing a pointer, you must specify in the documentation if passing NULL is allowed/well defined.
Another difference is a matter of readability: using references instead of pointers (when possible) makes the code less cluttered with * and ->.