noob-mathematician
noob-mathematician

Reputation: 101

Returning a reference and returning a value

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

Answers (5)

JPX
JPX

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

Christian Hackl
Christian Hackl

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 line int 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

M. Root
M. Root

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

463035818_is_not_an_ai
463035818_is_not_an_ai

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

Some programmer dude
Some programmer dude

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

Related Questions