1

So I'm learning C++ (coming from a Java background). I thought I understood how memory works on a high level (stack vs heap and pointers). To experiment, I wrote the following two toy functions:

 int* pntrToHeap(int val) {
     return new int(val);  
}

and

 int* pntrToStack(int val) {
     return &val;
}

At first I thought pntrToStack just wouldn't work, because the local variable val is on the stack which is "deleted" after the function exits. But after the following code worked without errors (with 1 warning, however), I reconsidered:

 int main()
{
    int val1 = *pntrToHeap(3);
    int val2 = *pntrToStack(4);
    cout << val1 << endl;
    cout << val2 << endl;
    return 0;
}

Both 3 and 4 printed to the screen. It seems as though the stack isn't actually deleted, but the CPU just loses the ability to access local variables on it -- is this correct? If so, in a case like this, which function should we prefer?

Lastly, since val1 is a local variable of main, is pntToHeap creating a memory leak since I can't delete the value it created on the heap?

I know these concepts have been asked about before, but I couldn't quite find the answers. Thanks!

Three
  • 127
  • 3
  • undefined behavior means: I might work, but there is no guarantee – 463035818_is_not_an_ai May 13 '15 at 11:40
  • 1
    So pntrToStack is undefined behavior? – Three May 13 '15 at 11:41
  • actually I am not sure what is the correct term. AFAIK it is completely valid to return this pointer, it just does not hold any meaningfull value once the function returns. – 463035818_is_not_an_ai May 13 '15 at 11:45
  • *Lastly, since val1 is a local variable of main, is pntToHeap creating a memory leak since I can't delete the value it created on the heap?* Precisely, even if `val1` has static storage duration you'll still be creating a memory leak. Second, your `pointerToStack` is bad, very bad, since you pass a variable by value, therefore you create a local copy of it in your function, and then you take it's address. At the exit from your function the local variable cease to exist and you are left with a dangling pointer. Pass by reference if you want your pointer to point to something persistent. – vsoftco May 13 '15 at 11:45
  • pntrToHeap does not create a memory leak. The above usage creates a memory leak as he throws the pointer returned by the function away, but that has nothing to do with the function itself. – Jonas May 13 '15 at 11:48
  • Okay, now I'm confused. Why doesn't pntToHeap create a memory leak? The value 4 is in some memory on the heap that I can never delete, right? – Three May 13 '15 at 11:49
  • @Jonas yes of course, the fact that OP doesn't save the pointer that's returned. – vsoftco May 13 '15 at 11:49
  • 1
    @Jonas, I see what you're saying. I could keep the pointer and then delete later. Thanks – Three May 13 '15 at 11:50
  • 1
    pntrToHeap essentially does the exact same thing as "new" it heap allocates an object and returns the reference. – Jonas May 13 '15 at 11:50
  • @Three yes, you need to save the pointer that's being returned by your function, so you can delete the memory later. C++ is not releasing the memory allocated dynamically, so it's your task to delete it. – vsoftco May 13 '15 at 11:50
  • 1
    @vsoftco, thanks. But the dangling pointer seems to work. I de-reference it and I get the correct value. Is this one of those things that just happens to work in this case, but may not always? – Three May 13 '15 at 11:51
  • You should google for RAII idiom. That explains how memory and other resources can be handled in C++. And technically you can delete val2 by 'delete &val2' but well not everything what is technically possible in C++ is good style. – DarthB May 13 '15 at 11:52
  • 1
    @Three yes, the OS didn't reclaim that small chunk of memory, and no other process wrote meanwhile into it, that's why. But it is Undefined Behaviour of the worst case. – vsoftco May 13 '15 at 11:52
  • 1
    @DarthB, I wouldn't actually write code like this; this was mostly just for making sure I understood memory. I'll definitely try and adopt the more modern approach. To everyone, thank you. I think I understand all of my questions now. – Three May 13 '15 at 11:54
  • 2
    @DarthB `delete &val2` is wrong, it will compile but won't do what you think. `val2` is not dynamically-allocated, so the compiler will release its memory (trying to do it manually results in UB). And the function `pntrToStack` is not OK since it returns a pointer to a local variable. – vsoftco May 13 '15 at 12:01
  • @vsoftco, I think DarthB mean 'delete &val1', but I also don't understand how that would delete what's on the heap, since at this point val1 is a copy that's local. – Three May 13 '15 at 12:05
  • @Three Right, you understand correctly, it won't. `delete &val1` has exactly the same issue. You should never delete a non-dynamically allocated variable. – vsoftco May 13 '15 at 12:10
  • 1
    Yes i meant, val1 but that's also UB. Did not think of this immediately. The only way this would work as expected is if val1 would be a reference instead a local copy. But well lets recap: Doing this for learning is good. I just gave one more example how fast you can make a mistake when doing things like that and dont think twice! ^^ – DarthB May 13 '15 at 12:13

1 Answers1

1

Definitely the first one! If you want something to live after the stack frame expires you should heap allocate it.

And yes, the value pointed to by the pointer returned from pntrToStack will be overwritten the next time you allocate a new stack frame ie. call a function. When you exit out of a scope the memory is not erased. It is merely marked as being free to allocate.

Jonas
  • 491
  • 6
  • 22
  • Oh I just removed the part of my question about val2, because I thought my premise was wrong, but you're saying it will be overwritten? I thought val2 would hold a copy of the value originally in the stack. – Three May 13 '15 at 11:42
  • Sorry, i thought I saw pointers. Yes, val2 will be a copy, but you are also misusing your functions if their intended usage is to generate a pointer to a value. Essentially val2 demonstrates that *(&val2) == val2 – Jonas May 13 '15 at 11:46