Reputation: 11
I got a question which is The function below may result in a run time error. Why? the code is :
int& sub(int& a , int& b){
int c = a - b ;
return c ;
}
how can I write code in main so there will be a run-time error?? thanks!!
Upvotes: 1
Views: 1571
Reputation: 2890
You're returning a reference to a local variable, which is an error. The local variable goes out of scope as soon as the function exists.
One of the answers above mentions:
Now, I will assume that you're asking this question because you're concerned what happens with larger data structures, and you're trying to prevent excess memory copies
While this is indeed true, this will not be an issue in many cases as most compilers will make use of return value optimization (RVO) / copy elision. Moreover, in modern C++ (i.e. C++11) we enjoy move semantics. Meaning, if you have a type T for which move construction is implemented and subtraction is defined:
T sub(const T& a, const T& b)
{
T c = a - b; // creates a new object of type T
return c; // the move is implicit
}
So when you call the function like this
// a, b already exists and are of type T
// c is move constructed as the right-hand side is a non-named r-value
T c = sub(a, b);
So even if T is an expensive-to-copy type, move-semantics can help keep performance and without having to use pointers and references. Bjarne Stroustrup says in his book "The C++ Programming Language",
Unfortunately, overuse of new (and of pointers and references) seems to be an increasing problem.
Upvotes: 0
Reputation: 73446
As it's undefined behaviour, there is no guaranteed portable error.
But here and example, betting on the gfact that nested calls will produce the referred result be overwritten.
int a = 5, b=4, c=2;
int r = msub(a, msub(b,c));
cout << "Should be 3: "<<r<<endl;
// output depends on compiler. I received 0, so incorect !
Here the online demo.
Needless to say that such errors are extremely nasty ! What happens here ?
msub(b,c)
the resutl is a temporary reference to the former local variable on the stack. At that moment, there's high probability, that the computed value of 2 is still there, even if the temporary variable doesn't exist anymore. I've tried to describe the general principle of the problem:
Upvotes: 2
Reputation: 179
This function will ALWAYS result in a runtime error, its just that you could get lucky and find your temp variable untouched on return (and usually will find this code executing properly if you us it "simply," which I will explain below). Lets consider what you're doing in this function.
int& sub(int& a , int& b)
This code means take the reference to the integer a and the reference to the integer b, return a reference to some other integer.
int c = a - b;
Take the value of variable a minus the value of variable b, store this in the temporary stack variable c.
return c;
Return a reference to the temporary stack variable c.
I hope that you see what the problem here is. The variable c is a temporary variable, and when the function returns, will go out of scope. So Consider the following two invocations of the function:
int some_other_function(int& x, int& y)
{
int a,b,c;
a = b = c= -1;
return x+y;
}
....
int a, b, c, d;
....
a = sub(b,c); //First call
d = some_other_function(sub(b,c),a); //Second call
...
The first call will likely perform as expected, because the temp variable stored on the stack inside sub will likely be intact, there are no function calls between when sub finishes execution and when the value of the reference returned by sub is assigned to the variable a, meaning nothing changes the stack.
In the second case, however, the sub() call will perform as expected, returning a reference to some_other_function(). But when some_other_function is called, it will trample on the same memory spaced used by sub(), meaning that it will almost certainly corrupt the temp memory location whose reference you took. The second call will fail, as long as sub(b,c) does not resolve to -1.
The easiest fix (and no doubt the fix you want, at least for this problem) is as follows:
int sub(int& a , int& b){
int c = a - b ;
return c ;
}
This will actually return a brand new integer not stored on the stack of sub(). Now, I will assume that you're asking this question because you're concerned what happens with larger data structures, and you're trying to prevent excess memory copies when passing data by value instead of by reference. I say this because passing an integer by reference saves no memory space, your function would actually be more efficient if it looked like this:
int sub(int a , int b){
return a - b ;
}
But, if you are trying to do this with a large data structure and attempting to eliminate excess by passing by reference instead of by value, you would want this:
class my_class;
my_class* sub(my_class& a, my_class& b)
{
my_class* c = new my_class(a-b);
return c;
}
And yes, you'd pretty much have to deal with dynamic memory allocation....this is the price of persistent data not stored on the stack.
Upvotes: 0