What happens to unused function return values? - c++

If I have a program:
#include <iostream>
using namespace std;
int TestIntReturn(int &x, int &y)
{
x = 1000;
y = 1000;
return x+y;
}
int main()
{
int a = 1;
int b = 2;
cout << a << " " << b << endl;
TestIntReturn(a,b);
cout << a << " " << b << endl;
}
what happens to the return value of TestInReturn(a,b) since it is unused?

Since you're talking about Windows, we'll assume an x86 processor.
In this case, the return value will typically be in register EAX. Since you're not using it, that value will simply be ignored, and overwritten the next time some code that happens to write something into EAX executes.
In a fair number of cases, if a function has no other side effects (just takes inputs and returns some result) the compiler will be able to figure out when you're not using the result, and simply not call the function.
In your case, the function has some side effects, so it has to carry out those side effects, but may well elide code to compute the sum. Even if it wasn't elided, it can probably figure out that what's being added are really two constants, so it won't do an actual computation of the result at run-time in any case, just do something like mov EAX, 2000 to produce the return value.

It is discarded; the expression TestInReturn(a,b) is a discarded-value expression. Discarding an int has no effect, but discarding a volatile int (or any other volatile-qualified type) can have the effect of reading from memory.

The return value simply gets discarded. Depending on the exact scenario the optimizer might decide to optimize away the whole function call if there are no observable side effects (which is not the case in your example).
So, upon return from TestIntReturn, the function will push the return value on the stack, the caller will then adjust the stack frame accordingly, but won't copy the returned value from the stack into any variable.

Nothing - it goes into the ether, and is not stored/used. The return value itself is an rvalue or temporary; I believe the compiler will optimize even the temporary creation out due to it not actually being used.

The return value is stored on the stack and popped off when the function returns. Since it is not being assigned to a variable by the caller, it is just discarded when the stack is popped.

Everybody answered correctly - the return value in this case is simply discarded, and in this specific example, you can ignore it.
However, if the return value is a pointer to memory allocated inside the function, and you ignore it, you'll have a memory leak.
So some function values you can't just ignore, but in this case - you can.

In the case of primitive types, nothing happens to it. It is
just ignored. In the case of class types, the returned object
will be destructed, without anything else happening to it.

Related

Implications of not assigning the return value of a function to a variable

I'm going through some introductory C++ exercises, one of which is: What's going to be on the screen after running this code:
int& testMethod (int& a){
int c = a+a;
return c;
};
int main() {
int z = 5;
int* y = new int (testMethod(z));
int r = 25;
testMethod(r);
std::cout<<*y;
return 0;
}
My questions are:
Am I right that this is an example of UB as the value returned by testMethod on the second call is not getting assigned to a variable?
Is it true that the return value, although not assigned to a variable, might still be recovered but it depends?
For No 2, I'm just trying to confirm my understanding of how the stack works, which is as follows. When a function returns a value and the value gets assigned to a variable, the result of the calculations is firstly stored on the stack as retval at some memory location and then gets assigned to the variable, i.e. written to another memory location. The stack pointer then moves up (again, from what I understand, the 'top' of the stack is actually its 'bottom' as the pointer moves from the largest address to the smallest). But retval is still there for some time until it gets overwritten by another piece of data (which might happen almost instantly).
This second question arose when I was looking for an answer to the first question on SO and found this thread, as the two top (by votes) posts answer differently.
How automatic allocation is implemented on your particular platform is irrelevant. Your codes does trigger UB, not because you ignore the return value of testMethod (which, by the way, is not a method) but on the contrary because the following line uses it:
int* y = new int (testMethod(z));
The issue is that testMethod always returns a dangling reference to what was its local variable c. Using this reference to initialize the dynamically-allocated int triggers UB.
Predictably, enabling warnings (which you should always do) produces the following:
warning: reference to stack memory associated with local variable 'c' returned [-Wreturn-stack-address]
Am I right that this is an example of UB as the value returned by
testMethod on the second call is not getting assigned to a variable?
Maybe you didnt notice yet, but you are ignoring the returned value all the time (sloppy speaking). For example std::cout << *y; returns a reference to std::cout, otherwise you could not chain it as in
std::cout << "hello" << "world";
No. Ignoring the returned value is not undefined. Sometimes you cannot avoid to ignore the returned value (just another example: assignment usually returns a reference, ie you can write a = b = c; but usually you just write b = c; a = b;).
For 2) you are too much considering implementation details. Dont overcomplicate it. You ignore the value, thats all.
PS: your code has UB, but for completely different reason (see other answer).

C++ functions and scope of variables

#include<iostream>
using namespace std;
void fun(int a) {
int x;
cout << x << endl;
x = a;
}
int main() {
fun(12);
fun(1);
return 0;
}
The output of this code is as follows:
178293 //garbage value
12
why are we getting 12 and not garbage value instead??
why are we getting 12 and not garbage value instead??
In theory, the value of x could be anything. However, what's happening in practice is that two calls to fun one after the other is responsible for the previous value of x to be still on the stack frame.
Let's say the stack frame is structured as below:
arguments
return value
local variables
In your case,
Memory used for arguments is equal to sizeof(int).
The compiler may omit using any memory for the return value since the return type is void.
Memory used for local variables is equal to sizeof(int).
When the function call is made the first time, the value in the arguments part is set to 12. The value in the local variables is garbage, as you noticed. However, before you return from the function, you set the value of the local variable to 12.
The second time the function is made, the the value of the argument is set to 1. The value in the local variable is still left over from the previous call. Hence, it is still 12. If you call the function a third time, you are likely to see the value 1 in the local variable.
Anyway, that's one plausible explanation. Once again, remember that this is undefined behavior. Don't count on any specific behavior. The compiler could decide to scrub the stack frame before using it. The compiler could decide to scrub the stack frame immediately after it is used. The compiler could do whatever it wants to do with the stack frame after it is used. If there is another call between the calls to fun, you will most likely get completely different values.
You have not initialized the value x when printing it. Reading from uninitialized memory is UB, i.e., there are no guarantees as to what will happen. It could output a random number, or invoke an unlikely combination of bits that will do something unexpected.
Reading an uninitialized integer is UNDEFINED BEHAVIOR, that means that it can do literally anything, can print anything. It can format your hard drive or collapse the observable universe! Basically I dont know compiler implementations that do so but theoretically they can!

Local Variables Being Passed ( C++)

I have encountered a problem in my learning of C++, where a local variable in a function is being passed to the local variable with the same name in another function, both of these functions run in main().
When this is run,
#include <iostream>
using namespace std;
void next();
void again();
int main()
{
int a = 2;
cout << a << endl;
next();
again();
return 0;
}
void next()
{
int a = 5;
cout << a << endl;
}
void again()
{
int a;
cout << a << endl;
}
it outputs:
2
5
5
I expected that again() would say null or 0 since 'a' is declared again there, and yet it seems to use the value that 'a' was assigned in next().
Why does next() pass the value of local variable 'a' to again() if 'a' is declared another time in again()?
http://en.cppreference.com/w/cpp/language/ub
You're correct, an uninitialized variable is a no-no. However, you are allowed to declare a variable and not initialize it until later. Memory is set aside to hold the integer, but what value happens to be in that memory until you do so can be anything at all. Some compilers will auto-initialize variables to junk values (to help you catch bugs), some will auto-initialize to default values, and some do nothing at all. C++ itself promises nothing, hence it's undefined behavior. In your case, with your simple program, it's easy enough to imagine how the compiler created assembly code that reused that exact same piece of memory without altering it. However, that's blind luck, and even in your simple program isn't guaranteed to happen. These types of bugs can actually be fairly insidious, so make it a rule: Be vigilant about uninitialized variables.
An uninitialized non-static local variable of *built-in type (phew! that was a mouthful) has an indeterminate value. Except for the char types, using that value yields formally Undefined Behavior, a.k.a. UB. Anything can happen, including the behavior that you see.
Apparently with your compiler and options, the stack area that was used for a in the call of next, was not used for something else until the call of again, where it was reused for the a in again, now with the same value as before.
But you cannot rely on that. With UB anything, or nothing, can happen.
* Or more generally of POD type, Plain Old Data. The standard's specification of this is somewhat complicated. In C++11 it starts with §8.5/11, “If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.”. Where “automatic … storage duration” includes the case of local non-static variable. And where the “no initialization” can occur in two ways via §8.5/6 that defines default initialization, namely either via a do-nothing default constructor, or via the object not being of class or array type.
This is completely coincidental and undefined behavior.
What's happened is that you have two functions called immediately after one another. Both will have more or less identical function prologs and both reserve a variable of exactly the same size on the stack.
Since there are no other variables in play and the stack is not modified between the calls, you just happen to end up with the local variable in the second function "landing" in the same place as the previous function's local variable.
Clearly, this is not good to rely upon. In fact, it's a perfect example of why you should always initialize variables!

Would it be more efficient to pass a variable to a function by reference than to make a function to return a variable?

So this seems like a fairly simple question, but I haven't been able to find an answer to it anywhere online. The reason I'm assuming a function which returns a variable is less efficient than a function which takes a variable and changes it is because I think the first would use more memory. However, I could be wrong, I'm not aware of how this affects processing time.
Here's two C++ examples:
This a function which returns a variable:
#include <iostream>
short getInput(){
short input;
std::cin >> input;
return input;
}
int main(){
short input = getInput();
}
You can see in this one that the program needs two input variables to be created, even if the second is only created for a brief amount of time.
This is a function which passes a value by reference:
#include <iostream>
short getInput(short& input){
std::cin >> input;
}
int main(){
short input;
getInput(input);
}
Not only is this example code segment shorter, it only initializes one short variable. Am I wrong on the fact that it's more efficient.
A value of a small, simple built-in type like short or int is almost certain to be returned in a register, so it won't involve creating anything.
If we simplified your code a tiny bit to something like return 1;, we'd expect the body (when we turned off optimization, so there was still code for anything at all) we'd end up with something like this:
mov rax, 1
ret
If the return value is not small enough to fit in a register, then the compiler is normally going to allocate space in the caller, and pass a hidden reference to that space to the function being called. In other words, it'll do essentially the same thing you're doing manually.
To make a long story short, you should write your code whichever way makes the most sense. If if makes the most sense for your function to return a value, then return a value. If it makes more sense to pass a reference, then do that.
There are a few cases where it makes real sense to modify a referenced variable instead of returning a value though. One is for something like a pop from a stack or a queue. If copying a return value might throw, then there can be a difference in exception safety. For example, you can do something like this:
template <class T>
class queue {
std::deque<T> data;
public:
void pop(T &t) {
t = data.front();
data.pop_front();
}
};
If you attempt to return the T by value, you can end up popping the value off the deque, but then its copy constructor throws when you try to copy the return value.
This way, however, you're only popping the value off the deque if the copy into the "return" value succeeds. If the copy throws, then the value remains on the deque.
I will attempt an answer, although I'm sure it is probably debatable. I strongly support returning by value instead of using output parameters for the following reasons:
Returning fundamental types by value is extremely efficient. Returning by value also allows "natural" function composition, such as
double result = sin(exponential(factorial(n)));
Imagine writing this with output parameters for all 3 functions.
Performance begins to matter whenever you return large class objects. However, in that case the compiler can (and does) perform the so called (named) return value optimization. This is an optimization scheme in which the (named) return value is constructed directly into the left hand side object (there are some restrictions, see the link). Furthermore, returning by value plays nicely with C++11 move semantics, so if you have a cheap-to-move object of some type, say Foo, you can write
my_already_constructed_object = some_function_that_returns_by_value();
and the move assignment operator will do its magic, which is effectively much cheaper than a deep copy (think of it more like a swap).

C++/C -assembly level questions

When a global variable is used inside a function(C/C++), whether it'll be taken directly from registers or from stack?
Why bound loops(for loops) are considered to have more scope for optimization than nobound loops(while loop/do while)?
Why returning a value is not as good as passing the value by reference?
If possible plz give assembly level descriptions.
1) It will be taken from an address allocated as part of the application load. ie A global variable is simply an address in the process's virtual address space. If that global has been used recently the compiler may be able to cache it in a register.
2) They don't.
3) Returning a value often requires a copy of the data. If the data is a simple type (such as int or float) then it can and will be returned via a register. If the object is too large to fit in a register then the compiler must allocate space for the object on the stack and then copy the data being returned into this allocated space. Passing the value as a reference is, usually, implemented by passing a pointer to the data. Therefore you return the value by modifying the data at that memory address directly. No copy takes place and hence its faster. Do note, though, that Return Value Optimisation (RVO) can mean that there is no win to passing the return value in as a reference. Equally,a s pointed out in the comments, C++0x's new move constructor can also provide the same bonuses as RVO.
No need to explain any of those using assembler examples, IMO.
1) Global variable is statically allocated by linker
(it can be an offset from module's base though, not
necessarily a fixed address).
Still, a function would usually read a global var from
a direct address, and a local var from offset + stack pointer
and a class field from offset + object base pointer.
The value of a global variable can be cached in a register
for subsequent reads, unless its declared "volatile".
2) Its not really a matter of for/do/while choice,
but how easy its to compute the number of iterations,
so that compiler would be able to decide whether to unroll
and/or vectorize and/or parallelize the loop.
For example, here the compiler would know the number
of iterations:
for( i=0; i<8; i++ ) { j = 1 << i; XXX }
and here it won't:
for( j=1; j<256; j<<=1 ) { XXX }
The for loops maybe just more frequently have a structure
which is easier to understand for compiler.
3) If its a value of basic type (char/short/int etc), its
slower to return it by reference (though sometimes compiler
can optimize this).
But for larger structures a reference/pointer can reduce
the amount of work for compiler, and it really may be faster
if compiler won't be able to avoid creating some temporary
copies etc.
Update:
Ok, here's a more specific example:
#include <stdio.h>
int main( void ) {
int a,b, i,j,s1,s2;
a = 123 + printf(""); // unknown in compile time
s1 = 1;
// bit reverse loop v1, gets unrolled
for( i=0; i<8; i++ ) { j = 1 << i; s1 += s1 + ((a&j)>0); }
s1 -= 256;
b = s1 + printf("");
// bit reverse loop v2, not unrolled
for( s2=1; s2<256; s2+=s2+(j>0) ) { j = b & s2; b -= j; }
s2 -= 256;
printf( "a=%02X s1=%02X s2=%02X\n", a, s1, s2 );
}
Asm listings for gcc/intelc are available here: http://nishi.dreamhosters.com/u/1.zip
First off you have not specified a target platform, arm, x86, 6502, zpu, etc.
1) When a global variable is used inside a function(C/C++), whether it'll be taken directly from registers or from stack?
You were not clear, so a global can be passed in by value, by reference or not passed in and used directly in the function.
passed by value depends on the code/compiler/target which you didnt specify. So the value or address to the global can go in a register or on the stack depending on the calling convention for that compiler/target. Items passed in by register sometimes have a placeholder on the stack in case the function needs more registers than are available. So passed by value the value the global contained is initially accessed either in a register or on the stack.
passed by reference is pretty much the same as passed by value, instead of the value the address to the global is passed in by register or on the stack depending on the compiler/target. Where this differs is that you can access the global directly from/to its memory location, but that is the nature of pass by reference.
used directly in the function then it depends on the code/compiler/target as to whether the global is accessed directly from its fixed memory location or if a register loads that memory location and the value is operated on from a register. The stack is not used in this case so the answer is either (non-stack) memory or register.
2) Why bound loops(for loops) are considered to have more scope for optimization than nobound loops(while loop/do while)?
Depends on the code, compiler, and target, I cannot think of a generic case where one is better than the other.
3) Why returning a value is not as good as passing the value by reference?
Very very subtle performance gain if anything. Depends heavily on the code, compiler, and target. There are cases where by reference is slightly faster and cases where by value is slightly faster. Comparing the two, the differences have to do with the number of times the address or data has to be copied to/from registers or the stack on its path. At best you may save a few mov or load/store instructions.
In the general case (being precise here is hard), globals are retrieved from memory but not from the stack (unless already cached in a register), loops can be optimized depending on the information that the compiler has on what the loop does (can it perform loop unrolling?) and in the third case it depends on the actual code. Since the first two have already been dealt with in other questions, I will focus on the third question.
There is a common optimization called (Named) Return Value Optimization (N)RVO that the compiler can perform to avoid unnecessary copies.
// RVO // NRVO // cannot perform RVO
type foo() { type bar() { type baz() {
value a; type a; type a,b;
// operate on a // modify a // pass a and b to other functions
return type(a); return a; if ( random() > x ) return a;
} } else return b;
}
In both foo and bar, the compiler is able to analyze the code and determine that the temporary type(a) in foo or the named local variable a in bar are the return value of the function, so it can construct those objects in place of the return value (according to the calling convention) and avoid copying it. Contrast that with baz where the compiler must create objects a and b before actually knowing which has to be returned. In this case the compiler cannot optimize anything, has to perform the operations and only at the end copy either a or b to the return value.
Whenever the compiler performs (N)RVO or if it is actually impossible to perform, changing the function signature to receive the object by reference will not provide a performance advantage and will make code at the place of call less readable for functions that create new objects.
This should be used as a general rule of thumb, but noting that as always, there are exceptions, and cases where one or the other might be slightly better performance wise. But for most cases, and unless measuring the performance proves otherwise, you should write the code as close to the design semantics as possible. If a function creates a new object, then return it by value, if a functions modifies an object, pass by reference.
Some special cases can be a function that creates vectors and is called in a tight loop, where having a single vector that is pass by reference, cleared in the function and then filled will reduce the number of memory allocations (clear() in a vector does not deallocate memory, so it does not need to reallocate it in the next iteration).
On the other end, when function calls are chained, and with the proper combination of return bay value and pass by value, you might avoid extra copies by not passing references in --a non-const reference requires a non-temporary object.