tags:

views:

171

answers:

6

If *get_ii() returned heap memory, rather than stack memory, would this problem be eliminated?

01 int *get_ii()  
02 {  
03    int ii;        // Local stack variable  
04    ii = 2;  
05    return ⅈ  
06 }  
07 main()  
08 {  
09   int *ii;  
10   ii = get_ii();  // After this call the stack is given up by the routine   
11                   // get_ii() and its values are no longer safe.  
12    
13   ... Do stuff  
14   ..  ii may be corrupt by this point.  
15 }  

Source - http://www.yolinux.com/TUTORIALS/C++MemoryCorruptionAndMemoryLeaks.html

thanks

+2  A: 

The problem in your code will occur because when you access ii in main, after get_ii() returns, your variable accessed through ii is already destroyed.

If you return a memory allocated over heap from get_ii, then the memory will be accessible till it is explicitly destroyed

Kisalay
+3  A: 

Right -- memory from the heap (allocated with malloc, for example) will be persistent outside of get_ii()'s scope. Just make sure to free it. You could also allocate declare ii as static int ii, in which case its pointer would exist outside outside of get_ii(), too.

maksim
Though, one caveat is that declaring it as a `static` then sets it up so there is one copy for all calls to the function. This is a design decision that should be made with forethought and understanding, and definitely not the right thing to do in a multi-threaded program.
Omnifarious
It doesn't even require threading to be a problem. If one spot in the program get the pointer and holds onto it, another spot could do the same thing and a change to the value in one place would effect the other.
KeithB
+7  A: 

Yes. Allocating from the heap would work here. Make sure that somewhere you release it again otherwise you'll leak memory.

Often smart-pointers help with this kind of "don't forget" logic.

djna
+1 for smart pointers. Not using RAII for this kind of thing is probably a bad idea.
Brian
Returning a value would almost certainly be better still. Even if the object is large enough that copying would be slower than allocation, most compilers would elide the copy anyway.
Mike Seymour
So the issue is that the returned address of ii means nothing once it's freed from the get_ii function?
Kevin
@Kevin: No, the address means that position in memory. It just so happens that the location it points to is inaccessible.
DeadMG
@Kevin: The problem is your pointing at an object who's lifetime has ended. No more, no less.
GMan
+3  A: 

You are basically returning the address of a variable which no longer exists (ii is created when the function get_ii() starts executing, and exists only until the function exits). Any access to the memory pointed by int *ii in main() causes undefined behavior.

On the other hand, heap memory is allocated when you explicitly request it, and is not released until you explicitly request it. So if you allocate a memory block inside a function, it is perfectly fine to return the pointer to that memory block to the caller. Just make sure to document who is responsible for freeing the memory block when it is no longer needed!

slacker
A: 

If you are writing C-style code, the thing to do is to pass in a pointer to an object and modify the object via that pointer. That way the get_ii function does not worry about where the object came from. The calling function takes care of it.

If you are writing C++-style, then you should return by value or return a smart pointer or take a reference and modify the object via that reference. Or you can use the C-style and pass a pointer. Some C++ authors prefer the pointer pass because it makes it clear that the object is being modified while a reference pass is not clear.

Now, if the object is small as it is in this example, you should always pass and return it by value. It is faster and cheaper than using a pointer and it makes the coding more simple.

Zan Lynx
Even if the returned object is big the return value optimization may allow the compiler to construct it in the place it it being returned to eliminating any copying.
John Burton
If you're returning a struct, the usual ABI actually passes a pointer to a struct to be filled in as the first argument, making it equivalent to the pass-a-pointer version. There are some differences due to potential exceptions (and possibly threads), but if you're assigning to a local, it should do the right thing (and might optimize better).
tc.
+2  A: 

even more nefarious:

std::string& makeString() //returns a reference
{ std::string str = "Dustin"; return str; }

main(){
std::string s = makeString();
//s is a dangling reference! makeString returns a reference to str, 
//but str is on the stack and goes out of scope, so we're keeping a reference to nothing
}

str (inside makeString) is on the stack and is destroyed when makeString returns. resolve this error by returning by-value instead of by-reference, which makes a copy of the str right before it goes out of scope.

Dustin Getz
I thought that stack variables get destroyed? Secondly, how does this error get resolved?
Kevin
updated my answer
Dustin Getz