Search code examples
c++cpointersmemorymemory-management

References to stack allocated variables that are out of scope


According to my understanding, stack allocated variables are disposed of when they go out of scope. However, the concept of returning references to variables that were allocated on the stack and subsequently accessing those references outside the scope in which the variable was declared confuses me. Would they not be pointing to memory that has now been deallocated? The only possibility that I can think of is that the memory is being copied to the location that the reference is pointing to.

Here is an example that I tried that prints 4, even though the object that it is referencing is technically out of scope.

#include <iostream>

class A {
    
    public:
        int x;
        A(int a) : x(a) {}
};


A& ref_func() {
    A obj {4};
    
    A& ret_val = obj;
    
    return ret_val;
    
}

int main()
{
    A& ret = ref_func();
    
    // shouldn't the object that ref_func is returning a reference to be deallocated?
    // why is it able to be accessed like normal below?

    std::cout << ret.x << std::endl;

    return 0;
}

And here is the same example in C, which prints 5.

#include <stdio.h>

int* ref_func() {
    
    int x = 5;
    
    int* y = &x;
    
    return y;
    
}

int main()
{
    int* ret = ref_func();
    printf("%d", *ret);
    
}

My question is why does this work? x is clearly out of scope, however the pointer that is returned by ref_func() is still pointing to the correct value of x.


Solution

  • When dereferencing a pointer to (or access a reference to) a variable whole lifetime has ended, you invoke undefined behavior.

    Undefined behavior means the behavior of the program can't be predicted. It could crash, it could output strange results, or (as in this case) it could appear to work properly. Also, a seemingly unrelated change such as adding an unused local variable or a call to printf for debugging can change the way undefined behavior manifests itself.

    What's probably happening in this case is that the memory that the variable had previously used wasn't repurposed for anything else, so the old value still happens to be there. But again, there's no guarantee of that. If you add something like printf("test"); before accessing ret you'll probably get different results.

    See also: https://stackoverflow.com/a/6445794/1687119