In this code, I reference the local variable b
even though it is out of scope. But I do it from within the same function so it's probably still on the stack, right? I ran the program and it worked but I'd like to know if it's guaranteed to work on all implementations.
#include <iostream>
void main()
{
int* a;
{
int b = 5;
a = &b;
}
std::cout << *a;
}
The problem here is not that
b
is out of scope. It is that the lifetime ofb
has ended. Scope is about where the name of an object is known. Lifetime is about when the object exists (within the computational model).Technically, the object
b
does not exist when you reference it with*a
. The bytes that were used to represent it might happen to be still unchanged in memory, and accessing them with*a
might happen to work sometimes, especially if optimization is not turned on, but it is undefined behavior.An object can still be accessible even though its name is not in scope. Here is an example of an object that is accessible during its lifetime even though it is not in scope:
In this code, the function
bar
may accessb
, even though it cannot see the name ofb
infoo
. Although control leaves the block in whichb
is created, execution of the block is merely suspended, not terminated. Sob
continues to exist even while the functionbar
is executing. Sob
will be out of scope, but the access will be during its lifetime.No, that's not guaranteed to work.
a
is dangling once the inner scope is exited, so any dereference of it results in Undefined Behaviour and nothing whatsoever is guaranteed.The spec says
b
is an object with automatic storage duration. So, when you are outside the object's block, the object does not exist anymore. You can jump before it and continue write to it, I believe, but not if you jump outside its block. That's too much stretching it.I put together this example to help demonstrate what's going on with memory allocation in a typical frame-based stack. See: Is the stack variable deallocated when it goes out of scope?. That question was closed as a duplicate.
In
testerA
, we capture the address of our local variablea
for future use. We do a similar thing withtesterB
, only this time we capture the address of the second integer variable,b
. Notice that we overwrite the memory fora
with the value44
- calling itf
in this function.You can inspect these values immediately after calling the functions to observe what's going on. We're literally re-using the same memory addresses - but there's no guarantee what format the data is in from a prior function call.
Inspecting the Stack
Sample Output