the output of the code is 30.But I am not sure how it is getting to it.
#include <iostream>
int &fun()
{
static int x = 10;
return x;
}
int main()
{
fun() = 30;
std::cout << fun();
return 0;
}
I am expecting that the output will be 10 but its showing 30. how?
Your fun gives a location of an int (since it returns a reference). That location is the static variable x which is initialized (once, conceptually before the program runs) to 10.
Then fun() = 30; is assigning that location. So x gets assigned to 30.
At last cout << fun() displays the content of that location.
If x was some automatic variable your code would have undefined behavior.
PS. A crude way of thinking about & unary reference like int &r = x; is that it sort-of "transforms" your code as: introduce a phantom pointer int *p = &x; (where p is some fresh variable not appearing elsewhere) and replace r with *p, so &r with p, everywhere in the scope of that r.
Related
Just started learning c++ and came across this example where the function is returning a reference to a local static variable.
int& fun() {
static int x = 10;
return x;
}
int main() {
int &z = fun();
cout << fun() << " ";
z = 30;
cout << fun();
return 0;
}
What does the line int &z = fun(); do? Are we storing a reference inside another reference? I'm new to the language and all I know is that reference variables refer to a variable just like an alias. Can anyone explain how this works?
Are we storing a reference inside another reference?
No, references aren't even required to have "storage". A reference is something to simplify programming. auto& thing = foo.get_value_reference(); and then using thing makes code easier to write and debug. thing doesn't even have to exist as a separate entity when you look at the final assembly code.
int orig;
int& a = orig;
int& b = a;
b is now a reference to orig - nothing else. You can't reference a reference.
Are we storing a reference inside another reference?
No, there is no reference to reference, at least in C\C++.
For me, a reference is just a different name for another variable, at the end, they are all referring to the same, single object. In more detail, abstractly, whenever you write int& a = b, all you have is still b, and there is no such thing called a, that ever exist. (a is just an alias of b)
Because of that, we can't have a different name of a name, that would sound a bit weird, since it does not actually refer to anything that exist.
In your case above, what int& fun() does is returning the actual static int x = 10;. And int &z = fun();, once again, refer directly the the actual static int x = 10;. Whatever z or anything, afterall, it is just static int x = 10, under different names.
This would be different if you remove the amphersand-& to int fun(), which returns a copied version of int x = 10;, which means now existed two different things: int x = 10 and a copy of int x = 10.
That's why C\C++ is memory-efficient, isn't it? You know when things get copied and when it does not, which helps optimization a lot!
Hope this helps!
First of all, a variable declared static inside a function is allocated when the program begins and deallocated when the program ends. Unlike normal local variables, it is safe to keep a reference to a static variable after returning from the function in which it is declared. It continues to exist and will keep its value.
Let's consider this function:
int& fun() {
static int x = 10;
return x;
}
Returning a reference to the static variable x is like returning the variable itself. We can increment the variable through that reference, for instance:
cout << fun()++ << endl;
cout << fun()++ << endl; // output: 11
cout << fun() << endl; // output: 12
This would not be possible if fun() returned the value of x (the integer 10) instead of a reference to variable x itself (whose value we can update).
int &z = fun() lets us refer to that same static variable through the name z in the same way:
int &z = fun();
cout << z++ << endl;
cout << z++ << endl; // output: 11
cout << z++ << endl; // output: 12
cout << fun() << endl; // output: 13
Both the function return type and z have to be references for the above to work.
If z were not a reference but an int z variable, we would be making a copy of the original value and incrementing that in place of the static variable x itself.
If the function return type were a value (instead of a reference), it would return the value of x, not a reference to x itself. In this case, int f(); int &z = f(); would try to take a reference to the temporary return value of the function. In fact, this code doesn't even compile.
Functions that return static variables (by reference or otherwise) have their uses. One of which is that a static variable inside a function is initialized at runtime, the first time we run through its declaration.
In the code below, init_x() is called when initializing the static variable x. This happens the first time fun() is called to retrieve the value of x.
int& fun() {
static int x = init_x();
return x;
}
int main() {
do_other_stuff();
fun()++; // init_x() is called here
fun()++;
fun()++;
}
Can we have a function calling at the left side of the expression?
This code snippet works well but how? How can a function calling can be at left side and please elaborate how this snippet is executing and working well and what if i wouldn't have used static int in function definition.Thanks in advance.
#include<iostream>
using namespace std;
int &fun()
{
static int x;
return x;
}
int main()
{
fun() = 10;
/* this line prints 10 on screen */
printf(" %d ", fun());
getchar();
return 0;
}
Any expression that returns a non-const lvalue can be on the left side of the assignment and function call is also an expression like any other. Since lvalue historically means exactly that - value on the left side this turns into a recursive definition. So instead you can consider an lvalue anything that you can take address of:
int x = 5;
&x; //valid, takes the address of the variable
&5; //invalid, integer literal has no address
int func1();
&func1(); //invalid, can't take the address of the temporary value
int &func2();
&func2(); //valid, since the function returned reference
//which itself is almost the same as the address
So any expression that results in something addressable can be assigned to. You can even do something like this:
int x = 0;
int y = 0;
int z = 5;
(z > 5 ? x : y) = 10;
As for your second question, if you remove static from your function you would return a reference to a local variable of the function. Local variables stop existing when the function exits, so you would return a reference to a variable that is already destroyed. This, however, will compile and run, but the results of that execution would be unpredictable that's why this is called undefined behavior.
code
#include<iostream>
using namespace std;
int &fun()
{
int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}
output wil be 10 , tell me how and when int x = 10 is changed to static int x = 10 output will be 30 .Explain both of the cases .
This is undefined behavior. You are returning a reference to a local variable whose lifetime has ended at the end of the function.
It's quite amusing what g++ does with this code:
At -O0, it prints 10.
At -O1, it prints 30.
At -O2 and -O3, it prints 0.
If you declare x as static, then it has static storage duration, which means that its lifetime doesn't end when the function returns, which means that it is legal to return a reference to it. All calls to foo will return a reference to the same int.
I was searching for explanations over reference variables in c++ and I found this:
#include<iostream>
int a=10; //global 'a' so that fun doesn't return a reference of its local variable
int & fun();
int main()
{
int p = fun(); //line to be noted
std::cout << p;
return 0;
}
int & fun()
{
return a;
}
This worked and so does this:
#include<iostream>
int a=10; //global 'a' so that fun doesn't return a reference of its local variable
int & fun();
int main()
{
int &p = fun(); //line to be noted
std::cout << p;
return 0;
}
int & fun()
{
return a;
}
My question is how could an integer variable store the value of reference as is being done in first code snippet [line number 6]. Isn't the correct syntax as depicted in code snippet 2 [at line 6], i.e. we should define a reference variable (int &p) to carry the reference and not a regular integral variable?
Shouldn't the compiler give an error or at least a warning? I am using GCC 4.7.1 64-bit.
Okay got it ... #chris : you were right..When I did this:
int p = fun();
p++;
std::cout << p << endl << a;
It showed the results to be 11 and 10. Hence only a's value is copied into p and p doesn't became the alias of a.
But when I tried the same with second code, it showed values of both a and p to be 11. Hence p became the alias of a.
No, it is fine either way.
The return value reference is not even necessary in this special case because you are not trying to modify the return value "on the fly" or the 'a' later, like when you use arithmetic operator overloads for that purpose, for instance
Please Explain the following code
#include <iostream>
using namespace std;
int main()
{
const int x = 10;
int * ptr;
ptr = (int *)( &x ); //make the pointer to constant int*
*ptr = 8; //change the value of the constant using the pointer.
//here is the real surprising part
cout<<"x: "<<x<<endl; //prints 10, means value is not changed
cout<<"*ptr: "<<*ptr<<endl; //prints 8, means value is changed
cout<<"ptr: "<<(int)ptr<<endl; //prints some address lets say 0xfadc02
cout<<"&x: "<<(int)&x<<endl; //prints the same address, i.e. 0xfadc02
//This means that x resides at the same location ptr points to yet
//two different values are printed, I cant understand this.
return 0;
}
*ptr = 8;
This line causes undefined behavior because you are modifying the value of a const qualified object. Once you have undefined behavior anything can happen and it is not possible to reason about the behaviour of the program.
Since x is a const int, the compiler will most likely, in the places where you use x, directly substitute the value that you've initialized with (where possible). So the line in your source code:
cout<<"x: "<<x<<endl;
will be replaced by this at compile time:
cout<<"x: "<<10<<endl;
That's why you still see 10 printed.
But as Charles explained, the behaviour is undefined, so anything could happen with code like this.