Reputation: 101
I am not quite sure that I have understood why there is a problem when we return the reference of a local random variable. So let's say that we have this example.
int *myFunc() {
int phantom = 4;
return &phantom;
}
Then the usual argument is that when the function is used, the memory of the variable phantom
is no longer available after the execution of the code line int phantom = 4;
so it cannot be returned (at least this is what I have understood so far). On the other hand, for the function,
int myFunc() {
int phantom = 4;
return phantom;
}
the value of the integer variable phantom
will return. (I see the returning of the value as the dereferencing of an underlying pointer for the variable phantom
).
What do I miss here?? Why in the first case there is a compilation error and in the second case everything works??
Upvotes: 0
Views: 158
Reputation: 93
The first case
int* myFunc()
{
int phantom = 4;
return &phantom; // you are returning the address of phantom
} // but phantom will not "exist" outside of myfunc
Doesn't work because variable phantom
is a local variable and it lives only during the execution of myfunc
. After that, it's gone.
You are returning an address of a variable, that will practically "not exist" any more.
The rule: never return pointers or references to local variables.
This is OK:
int myFunc()
{
int phantom = 4;
return phantom; // you are returning by value;
// it doesn't matter where phantom "lives"
}
int main()
{
int x = myFunc(); // the value returned by myFunc will be copied to x
}
Upvotes: 0
Reputation: 27528
I am not quite sure that I have understood why there is a problem when we return the reference of a local random variable
Because the C++ standard says it is undefined behaviour if you use such a function, and you want to avoid undefined behaviour in your program. What your program does should be determined by the rules of the C++ language, not be random.
Note that you return a pointer and not a reference. But it's undefined behaviour in both cases.
Then the usual argument is that when the function is used, the memory of the variable
phantom
is no longer available after the execution of the code lineint phantom = 4;
so it cannot be returned (at least this is what I have understood so far).
This is an implementation-centric point of view and may aid you in understanding the problem.
Nevertheless, it's important to distinguish between the observable behaviour of a program and the compiler's internal tricks to produce that behaviour. You don't even know whether any memory is occupied by a variable anyway. Considering the "as-if" rule and compiler optimisations, the entire function may have been removed, even if the behaviour was defined. That's just one example of what might really happen behind the scenes.
But again, it's undefined behaviour anyway, so anything may happen.
The question is, then, why does the C++ standard not define a behaviour for the case when you return a pointer like this and then try to access the pointee? The answer to that would be that it doesn't make sense. The object named by the local variable phantom
ends its life when the function returns. So you would have a pointer to something which no longer exists, yet it's still an int*
, and dereferencing a non-nullptr
int*
should yield an int
. That's a contradiction, and the C++ standard just does not bother to resolve such a meaningless situation.
Note how this observation is based on C++ language rules, not on compiler-implementation issues.
Why in the first case there is a compilation error and in the second case everything works??
It's certainly a warning and not an error, unless your compiler options are such that every warning is turned into an error. The compiler must not reject the code, because it's not ill-formed.
Still, your compiler tries to be helpful in the first case, because it wants to keep you from creating a program with undefined behaviour.
In the second case, the behaviour is not undefined. Returning by value means that a copy is made of the object which you want to return. The copy is made before the original is destroyed, and the caller then receives that copy. That's not meaningless and not a contradiction in any way, so it's safe and defined behaviour.
In the first case, returning by value does not help you, because although the pointer itself is safely copied, its contents are what eventually causes undefined behaviour.
Upvotes: 0
Reputation: 1
Try returning the pointer and dereference it to get the value.
#include <iostream>
using namespace std;
int *myFunc()
{
int number = 4;
int *phantom = &number;
return phantom;
}
int main()
{
cout << myFunc() << endl; //0x....
cout << *myFunc() << endl; //4
return 0;
}
Upvotes: -1
Reputation: 122458
You dont miss much. Only that in the first case there will be no compiler error.
[...] the memory of the variable phantom is no longer available after the execution of the code line int phantom = 4; so it cannot be returned
No, it can be returned and compilers may issue a warning for that but afaik no error. However, you should not!!
Btw, the memory is available, but it is undefined behaviour to access it after the function returned (not after the line int phantom = 4;
).
In the second case:
I see the returning of the value as the dereferencing of an underlying pointer for the variable phantom
You are thinking too complicated here. Returning a value from a function may be implemented by using a pointer, but thats an implementation detail. The only thing you have to care about here is that what is returned is the value. So no problems in the second case.
Upvotes: 0
Reputation: 409176
The first doesn't return a reference, it returns a pointer. A pointer to a local variable who will go out of scope once the function ends, leaving you with a stray pointer to a variable that doesn't exist anymore. That's why you get a compiler warning (usually not an actual error).
The second code copies the value. The local variable inside the function will never need to be referenced or used once the return
statement finished.
Upvotes: 2