0
int& foo()
{
    int i = 4;
    return i;
}

int main()
{
    int& j = foo();
    cout << j << endl;
    cout << j << endl;
    cout << j << endl;
    cout << j << endl;
    cout << j << endl;
    cout << j << endl;
    return 0;
}

In here, I would expect the first cout of j to output garbage because of the fact that the local variable i, which j is referencing, has gone out of scope. However, it seems consistently the first cout statement outputs the correct value that would be outputted if i was still in scope which is 4. After that, every cout statement prints garbage that is the same value. Here is an example of some output I've been getting:

4
528494
528494
528494
528494
528494
Press any key to continue . . .

Why is j not immediately printing out garbage the first cout statement. Shouldn't i have already gone out of scope?

Enryu
  • 1,406
  • 1
  • 14
  • 26

1 Answers1

0

The rule is not "using a variable after it has passed out of scope gives garbage output". It is that using a reference to a variable that has gone out of scope is undefined behaviour according to all C++ standards.

Undefined behaviour means the C++ standard provides no guarantee whatsoever about what happens. A consequence is that, when behaviour is undefined, any actual observable result is permitted. Garbage output is only one possible observable result.

That means any explanation of the behaviour you're seeing will be specific to your implementation (compiler, your chosen optimisation or debugging settings, etc, memory management by your host system, ....). The behaviour may also vary over time, since - when behaviour is undefined - there is no requirement that any particular behaviour occurs consistently.

As a generic explanation, in your specific case, it is probably related to how your compiler manages usage of machine registers by your program. The variable i in foo() may be stored in a register, then that register may not be cleared immediately, so the value 4 is retrieved from it in the first cout << j << endl statement. The working of output streams (implementation of operator<<() or endl) may then use the same register internally - since there is absolutely no way that C++ code with well-defined behaviour can access those registers directly - and therefore overwrite it.

But that's just a guess. As I said, it depends on the implementation - that's why I used the word "may" so liberally in the preceding paragraph. When behaviour is undefined (by the standard) then a compiler is permitted to do anything. You could see a completely different behaviour by tweaking optimisations settings or next time you update your compiler. Different compilers may do things completely differently as well.

Peter
  • 35,646
  • 4
  • 32
  • 74