7

I've been using C++ for a bit now. I'm just never sure how the memory management works, so here it goes:

I'm first of all unsure how memory is unallocated in a function, ex:

int addTwo(int num)
{
    int temp = 2;
    num += temp;
    return num;
}

So in this example, would temp be removed from memory after the function ends? If not, how is this done. In C# a variable gets removed once its scope is used up. Are there also any other cases I should know about?

Thanks

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
jmasterx
  • 52,639
  • 96
  • 311
  • 557
  • Retagged as 'C' because there's no C++ here, as pointed out by someone else below. – ChrisInEdmonton Dec 10 '09 at 13:45
  • 6
    Tetagged as C++, becaue this is definitely a C++ question, and the questioner explicitly asks about C++. –  Dec 10 '09 at 13:47
  • 9
    OP, there is no requirement that you accept any of the answers. –  Dec 10 '09 at 14:08
  • 1
    OP, there might be a requirement to sorth through all the comments, though ;) – peterchen Dec 10 '09 at 14:22
  • @San Jacinto No it isn't. There is no contract, implied or otherwie, between questioners and answerers. If he doesn't want to accept, for whatever reason, that's his right - he certainly doesn't have to explain himself. This issue has been done to death on meta, BTW. –  Dec 10 '09 at 15:35
  • @Neil, San Jacinto: please do not debate it here... To the point now, what do you mean by "removed from memory" ? Physically (overwritten) or Conceptually (should not be accessed, invokes undefined behavior, but you could get away with it) ? – Matthieu M. Dec 10 '09 at 15:42
  • In my humble opinion, the stack is a highly underrated memory management scheme. One issue I have with languages that have built in garbage collection is that they so rarely use the stack in an intelligent way. Also, good support for stack storage is part and parcel of allowing complex data types to be embedded inside other data types rather than referenced via a pointer. And this is also a huge win in many cases. – Omnifarious Dec 10 '09 at 16:32
  • @Omnifarious The stack has nothing to do with allowing objects to contain other objects, at least in C++. For example, if you create an object using "new", nothing is created on the stack. –  Dec 10 '09 at 16:57
  • @Neil, name me a language in which variables with complex structure can be stored on the stack but not inside other structures. They don't have anything to do with each other directly, but they are related ideas. – Omnifarious Dec 10 '09 at 20:08
  • @Omnifarious they really aren't related. In either regard, you give the strutures a place and room to live, and they are mapped out in memory at their starting address. It has absolutely nothing to do with stack space vs. heap space. the only difference comes when its time to destroy those structures and free them because you need to determine whose job it is. – San Jacinto Dec 10 '09 at 20:26
  • @Omnifarious you do gain the advantage though that when you declare your objects entirely, 100% on the stack (this means no pointers to heap-space in the objects) that you will likely have less memory fragmentation. – San Jacinto Dec 10 '09 at 20:28
  • @Omnifarours "name me a language in which variables with complex structure can be stored on the stack but not inside other structures" - I never remotely suggested any such thing. –  Dec 10 '09 at 20:33
  • This code is plain C. Therefore there is no C++ memory management going on here. This would only be the case if "`new`" would be used to create temp. – RED SOFT ADAIR Dec 10 '09 at 13:42

11 Answers11

20

In C++ there is a very simple rule of thumb:

All memory is automatically freed when it runs out of scope unless it has been allocated manually.

Manual allocations:

  • Any object allocated by new() MUST be de-allocated by a matching delete().
  • Any memory allocated by malloc() MUST be de-allocated by a matching free().

A very useful design pattern in C++ is called RAII (Resource Acquisition Is Initialization) which binds dynamic allocations to a scoped object that frees the allocation in its destructor.

In RAII code you do not have to worry anymore about calling delete() or free() because they are automatically called whenever the "anchor object" runs out of scope.

Thorsten79
  • 10,038
  • 6
  • 38
  • 54
12

Here, temp is allocated on the stack, and the memory that it uses is automatically freed when the function exits. However, you could allocate it on the heap like this:

int *temp = new int(2);

To free it, you have to do

delete temp;

If you allocate your variable on the stack, this is what typically happens:

When you call your function, it will increment this thing called the 'stack pointer' -- a number saying which addresses in memory are to be 'protected' for use by its local variables. When the function returns, it will decrement the stack pointer to its original value. Nothing is actually done to the variables you've allocated in that function, except that the memory they reside in is no longer 'protected' -- anything else can (and eventually will) overwrite them. So you're not supposed to access them any longer.

If you need the memory allocated to persist after you've exited the function, then use the heap.

int3
  • 12,861
  • 8
  • 51
  • 80
8

The local variable temp is "pushed" on a stack at the beginning of the function and "popped" of the stack when the function exits.

Here's a disassembly from a non optimized version:

int addTwo(int num)
{
00411380  push        ebp  
00411381  mov         ebp,esp             //Store current stack pointer
00411383  sub         esp,0CCh            //Reserve space on stack for locals etc
00411389  push        ebx  
0041138A  push        esi  
0041138B  push        edi  
0041138C  lea         edi,[ebp-0CCh] 
00411392  mov         ecx,33h 
00411397  mov         eax,0CCCCCCCCh 
0041139C  rep stos    dword ptr es:[edi] 
    int temp = 2;
0041139E  mov         dword ptr [temp],2 
    num += temp;
004113A5  mov         eax,dword ptr [num] 
004113A8  add         eax,dword ptr [temp] 
004113AB  mov         dword ptr [num],eax 
    return num;
004113AE  mov         eax,dword ptr [num] 
}
004113B1  pop         edi  
004113B2  pop         esi  
004113B3  pop         ebx  
004113B4  mov         esp,ebp                 //Restore stack pointer
004113B6  pop         ebp  
004113B7  ret        

The terms "pushed" and "popped" are merely meant as an analogy. As you can see from the assembly output the compiler reserves all memory for local variables etc in one go by subtracting a suitable value from the stack pointer.

Andreas Brinck
  • 51,293
  • 14
  • 84
  • 114
  • 3
    Not precisely how the stack is used. The function call will allocate a frame on the stack, but no pushes and pops take place. –  Dec 10 '09 at 13:39
  • 1
    @Neil I know, It was meant as an analogy which would be easier to understand. Added quotes and some assembly output – Andreas Brinck Dec 10 '09 at 13:46
  • 2
    push+pop are merely concepts - sure temp is pushed/popped off the stack. The implementation happens to be compiler+architecture dependant, and generally you can expect that the entire frame will be "pushed" and "popped" as one. For historical reasons the focus of the stack implementation is such that the terminology used differs, but we're still talking about placing and removing data from a last-in-first-out data structure: push and pop are certainly not *incorrect* terms for that. – Eamon Nerbonne Dec 10 '09 at 13:47
  • 1
    The code makes my point. Theere are no pushes and pops for the local variables, only for the return addresses etc. The storage for the local variables is created by adjusting the stack pointer, and then accessed by indexing. –  Dec 10 '09 at 13:49
  • ahh, you mean the push/pop *instructions* on x86. Fair enough, that's definitely confusing :-). – Eamon Nerbonne Dec 10 '09 at 15:49
  • @Eamon It's not x86 specific. I'm not aware of any CPU architecture that uses a stack where pushes and pops would (or could) be used. –  Dec 10 '09 at 16:15
  • @Neil Butterworth i think I'm misunderstanding you. The HC11/HC12 has push and pop instructions for manipulating the stack. It's entirely up to my compiler how values get on the stack. Could you elaborate a little bit? – San Jacinto Dec 10 '09 at 16:37
  • @Neil Butterworth are you referring to the placement of local variables? In that case, then I definitely can't see a compiler deciding to push, unless it is 'smart' enough to recognize an initialization that is no larger than the size of the register and also no larger than the data that the push/pop instructions can support. All that effort in compiler construction would seem rather over the top when you can just decrement the SP and move. – San Jacinto Dec 10 '09 at 16:41
6

Its not removed from memory once the function exits.

It remains in memory, in addTwo's stack frame, until some other process (or the same) re uses that portion of memory.

Until that point, accessing temp is undefined behaviour.

Tom
  • 43,810
  • 29
  • 138
  • 169
  • 5
    True, and this can be important for certain work. However, for most of us, conceptually the memory used by temp is no longer available once the function completes. – tloach Dec 10 '09 at 13:41
  • 1
    This is never relevant behavior unless you've a pointer to temp. And when you do, this is still never "important for some work" behavior since it's simply a bug. It's worth being aware of the fact that accessing unallocated memory on the stack or heap may result in undefined behavior (i.e. won't necessarily crash or cause an error). I can't see how this matters for any non-buggy functionality. – Eamon Nerbonne Dec 10 '09 at 13:56
  • @eamon: All I meant was that for certain work it is important to be aware that your stack size will not shrink just because a bunch of local variables go out of scope. For people who work on hardware where every byte matters being aware of this behavior can inform a decision to allocate space on the stack or the heap. – tloach Dec 10 '09 at 14:14
3

temp is allocated on the stack. So when the function returns, it is gone.

C++ scope rules are similar to C#.

Kristopher Johnson
  • 81,409
  • 55
  • 245
  • 302
2

Normally memory managment is used in the context of dynamic memory that is created by

new
malloc

In the normal code C++ behaves like every other language. If you create a variable or return it, it is copied and accessible on the target side.

int a = addTwo(3);

gets a copy of your returned value. If the returned value is a class copy operator called. So as long as you do not work with new and malloc you do not have to care about memory managment that much.

One additional remark which is important

void func(std::string abc)
{
  // method gets a copy of abc
}

void func(std::string& abc)
{
  // method gets the original string object which can be modified without having to return it
}

void func(const std::string& abc)
{
  // method gets the original string object abc but is not able to modify it    
}

The difference of the three lines is very important because your program may spare a lot of time creating copies of input parameters that you normally didn't want to create.

e.g.

bool CmpString(std::string a, std::string b)
{
  return a.compare(b);
}

is really expensive because the strings a and b are always copied. Use

bool CmpString(const std::string& a, const std::string& b)

instead.

This is important because no refcounted objects are used by default.

Totonga
  • 4,236
  • 2
  • 25
  • 31
1

Please see my answer to this question. It may clear up a lot of things for oyu.

How does automatic memory allocation actually work in C++?

I'm not just posting a link for giggles. My answer there is an in-depth look (at a very introductory level) how memory management works.

Community
  • 1
  • 1
San Jacinto
  • 8,774
  • 5
  • 43
  • 58
0

Variable temp is stack allocated. That means it's deallocated when the function returns.

See e.g.:

Sebastian
  • 4,802
  • 23
  • 48
0

In this case both num and temp are local to this function. When the function is called the number passed into num is copied from the caller to a variable on the stack. Temp is then created on the stack. When you return the value of num is copied back to the caller, and the temp and num variables used in the function are dropped.

tloach
  • 8,009
  • 1
  • 33
  • 44
0

In C,C++ local variables have automatic storage class and are stored in Stack.

When function returns then stack gets unwound and locals are no more accessible, but they still persist in memory and that's the reason when u define a variable in function it may contain garbage value.

It is just stack pointer manipulation in stack and on memory for local is removed actually.

David Sykes
  • 48,469
  • 17
  • 71
  • 80
Ashish
  • 8,441
  • 12
  • 55
  • 92
0

In C++, any object that you declare in any scope will get deleted when the scoped exits. In the example below, the default constructor is called when you declare the object and the destructor is called on exit, ie, ~MyClass.

void foo() {
  MyClass object;
  object.makeWonders();
}

If you declare a pointer in a function, then the pointer itself (the 4 bytes for 32 bit systems) gets reclaimed when the scoped exits, but the memory you might have allocated using operator new or malloc will linger - this is often known as memory leak.

void foo() {
  MyClass* object = new MyClass;
  object->makeWonders();
  // leaking sizeof(MyClass) bytes.
}

If you really must allocate an object via new that needs to be deleted when it exits the scope then you should use boost::scoped_ptr like so:

void foo() {
  boost::scoped_ptr<MyClass> object(new MyClass);
  object->makeWonders();
  // memory allocated by new gets automatically deleted here.
}
rui
  • 11,015
  • 7
  • 46
  • 64