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.
Related
This is an example problem to demonstrate the use of references in c++. i'm a beginner and this is my first time learning about references. i don't understand why we use &fun(). what does it mean?
#include<iostream>
using namespace std;
int &fun(){
static int x = 10;
return x;
}
int main(){
int &y=fun();
y = 20;
cout<<fun();
}
output : 20
Equivalent syntax is int& fun().
So this function returns a reference to 'x' (that is static), so later in main you can modify it (y = 20 does change the x inside the function).
So another invocation returns 20, as the x had been changed.
int & means fun() is returning a reference to an int. In main(), that reference is assigned to y, and the value of y is modified to 20, also changing the value of x to 20.
i have written this little program to explain my point and my variable a remains unchanged it prints 4. I later learned that I need to use pointers or references; why is that?
#include <iostream>
void setToTen(int x) { x = 10; }
int main(){
int a = 4;
setToTen(a);
std::cout << a << std::endl;
}
In C++ arguments to functions are passed by value. This means that when you write
setToTen(a);
the parameter int x in setToTen is given a copy of the value stored in the variable a. In other words, you're not actually handing off the variable a into the setToTen function. Instead, you're giving a copy of that value to setToTen, so the changes made in that function affect the copy rather than the original.
On the other hand, if you change setToTen so that it takes its parameter by reference, like this:
void setToTen(int& x) {
x = 10;
}
the story is different. Here, calling setToTen(a) essentially hands the variable a into the function setToTen, rather than a copy of the value. That means that changes made to the parameter x in setToTen will change the variable a.
Your code requests a copy of x by having the signature void setToTen(int x).
Being able to take things by copy means that reasoning about the behavior of a function is far easier. This is true both for you, and for the compiler.
For example, imagine this:
int increase_some( int x, int y, int z ) {
for (int i = 0; i < y; ++i )
x+=z;
return x;
}
because x y and z are copies, you can reason about what this does. If they where references to the values "outside" of increase_some, the bit where you x+=z could change y or z and things could get crazy.
But because we know they are copies, we can say increase_some returns x if y<=0, and otherwise returns x+y*z.
Which means that the optimizer could change it to exactly that:
int increase_some( int x, int y, int z ) {
if (y<=0) return x;
return x + y*z;
}
and generate that output.
This is a toy example, but we took a complex function and turned it into a simple one. Real optimizers do this all the time with pieces of your complex function.
Going one step further, by taking things by immutable value, and never touching global state, we can treat your code as "functional", only depending on its arguments. Which means the compiler can take repeated calls to a function and reduce them to one call.
This is so valuable that compilers will transform code that doesn't have immutable copies of primitive data into code that does before trying to optimize -- this is known as static single assignment form.
In theory, a complex program with lots of functions taking things by reference could be optimized this same way, and nothing be lost. But in practice that gets hard, and it is really easy to accidentally screw it up.
That is the other side; making it easier to reason about by people.
And all you have to embrace is the idea of taking arguments by value.
Function parameters are function local variables that are not alive after exiting function.
You can imagine the function definition and its call
int a = 4;
setToTen(a);
//...
void setToTen(int x) { x = 10; }
the following way
int a = 4;
setToTen(a);
//...
void setToTen( /* int x */ ) { int x = a; x = 10; }
As it is seen within the function there is declared a local variable x which is initialized by the argument a. Any changes of the local variable x do not influence on the original argument a.
If you want to change the original variable itself you should pass it by reference that is the function will deal with a reference to the variable. For example
void setToTen(int &x) { x = 10; }
In this case you can imagine the function definition and its call the following way
int a = 4;
setToTen(a);
//...
void setToTen( /* int x */ ) { int &x = a; x = 10; }
As you see the reference x is as usual local. But it references the original argument a. In this case the argument will be changed through the local reference.
Another way is to declare the parameter as pointer. For example
void setToTen(int *x) { *x = 10; }
In this case you have to pass the original argument indirectly by its address.
int a = 4;
setToTen( &a );
Take the following code, where a function returns by reference:
#include <cstdio>
using namespace std;
int & myFunction(int & input) {
return input;
}
int main() {
int x;
int y = 10;
x = myFunction(y);
printf("x is %d\n",x); // x is 10
printf("y is %d\n",y); // y is 10
x = 20;
printf("x is %d\n",x); // x is 20
printf("y is %d\n",y); // y is 10
return 0;
}
Except the obvious pitfall of returning a reference to a local variable of the function (which is not the case here), are there any things to watch out for in this kind of setup? In other words, is there anything "more" to this code than a function which simply returns things by reference in order to avoid unnecessary copying operations?
Except the obvious pitfall of returning a reference to a local
variable of the function (which is not the case here), are there any
things to watch out for in this kind of setup?
No, not really, it's perfectly valid but it has no advantage either. (in the current state of myFunction)
in order to avoid unnecessary copying operations?
There's still a copy being made here:
int x;
int y = 10;
x = myFunction(y); // value of y is copied to x.
This is less readable and doesn't speed up anything when it comes to just normal initialization:
int x;
int y = 10;
x = y;
There's no reason to do this in this situation, just stick to normal initialization.
Of course, if myFunction adds some kind of modification to a more complex object than int& then you can take advantage of returning the reference as you can then:
chain.method().calls();
The code you provided works because you're passing the variable to your function by reference, and still returning it by reference. This is consistent and works, but is weird. Why would you return the same variable that you're passing by reference? (I just remembered from the comments that this is useful for chaining in std::ostream, for example.)
On the other hand, if you pass that variable by value, you'll have a dangling reference and it won't work. So this won't work:
int & myFunction(int input) {
return input;
}
In my opinion, the only return by reference I find appropriate is if you return a variable from inside a class's method. Besides that, I don't think you should return by reference at all.
You can catch a variable as a constant reference and avoid copying it if you want without having a dangling if you do this:
int myFunction(int input) {
return input;
}
int main()
{
const int& myInt = myFunction();
//myInt is still valid here
}
This is a special case that.
I recently read about references in C++. I am aware of basic properties of references but I am still not able to figure out why following two programs produce different output.
#include<iostream>
using namespace std;
int &fun()
{
static int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}
This program prints 30 as output. As per my understanding, the function fun() returns a reference to memory location occupied by x which is then assigned a value of 30 and in the second call of fun() the assignment statement is ignored.
Now consider this program:
#include<iostream>
using namespace std;
int &fun()
{
int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}
This program produces the output as 10. Is it because, after the first call, x is assigned 30, and after second call it is again overwritten to 10 because it is a local variable? Am I wrong anywhere? Please explain.
In the first case, fun() returns a reference to the same variable no matter how many times you call it.
In the second case, fun() returns a dangling reference to a different variable on every call. The reference is not valid after the function returns.
When you use
fun() = 30;
in the second case, you are setting the value of a variable that is not valid any longer. In theory, that is undefined behavior.
When you call fun() the second time in the second case, the variable x is set to 10. That is independent of the first call to the same function.
Just adding to what has been said. The reason behind the first case's behavior is because it is a static variable, which has a static duration. Static duration means that the object or variable is allocated when the program starts and is deallocated when the program ends.
This means that once x in the first case has been initialized the first time with 10, the next function call will ignore static int x = 10; because x cannot be instantiated again, as it has already been allocated, and will simply proceed to return x;, which will be the same x that was assigned 30 in main.
Basically, your understanding is right, except for in 2nd case, you're processing a dangled reference of the local variable has been invalid, which is undefined behaviour, means anything is possible. What you said is just one of the possibility, it also could result in others, such as getting a random number, program crash, etc.
So I just had a thought, is it possible to return a parameter sent when a function is called. And if it is, is this considered fine or is it bad style?
Example:
int main()
{
...
int value = 1;
value = Foo(value);
...
}
int Foo(int i)
{
i = i * 2;
return (i);
}
As the parameter is being passed in and returned by value, this is fine - there is an implicit copy occurring when you call the function and when it returns.
For example
int value=1,other=0;
other=Foo(value);
other is now 2, value will still be 1
If you were passing in a reference or pointer then you would potentially run risks.
e.g. if the signature of Foo was
int Foo( int &i )
Then after the code chunk I used above, both other and value would be 2
There's no problem with "returning a parameter" in your example. You are not really "returning a parameter" at all. You are simply using the parameter in the argument expression of return. It is the result of that expression (the value of i) that gets returned, not the parameter itself.
One can argue that the "undesirable" property of your code sample is the fact that you are modifying the parameter inside the function, i.e. you are using the parameter as an ordinary local variable. There's nothing formally wrong with it, but sometimes people prefer to preserve the original parameter values throughout the function body. I.e. from that point of view your function would look better as
int Foo(int i)
{
return i * 2;
}
or as
int Foo(int i)
{
int i2 = i * 2;
return i2;
}
but, again, it is not really about "not returning a parameter", but rather about leaving the original value of i untouched inside the function.
There's no problem with doing that and it makes it very clear what's going on.
That's one valid approach to do this, but you might also like the idea of passing by reference:
int main()
{
...
int value = 1;
Foo(value);
...
}
void Foo(int &i)
{
i = i * 2;
}
The drawback to this approach is that you have to pass what's called an lvalue into the function-- basically, something that can be on the left side of an assignment statement, which here means a variable. A call with a literal or temporary, such as Foo(2), will fail to compile. The way you had written it originally will instead do an implicit copy by value into the local scope of the Foo function. Note that the return value is now also void.
Technically, there is no problem, but semantically, it is not advisable: in most cases the input of the function and the return value of the function are not the same, so you are reusing the variable to mean something different. It is clearer in next example
int main()
{
double i = 5;
i = getSquareSurface(i); // i was a length and is now a surface
}
This should be:
int main()
{
double length = 5;
double surface = getSquareSurface(length);
}
Of course, there are cases like the addOne() or in this case the Foo() function where the meaning doesn't change.