views:

185

answers:

6

I noticed that there are two ways to create C++ objects:

BTree *btree = new BTree;

and

BTree btree;

From what I can tell, the only difference is in how class objects are accessed (. vs. -> operator), and when the first way is used, private integers get initialized to 0.

Which way is better, and what's the difference?

How do you know when to use one or the other?

A: 

Well, they're being stored in quite different regions of memory.

Here's a good read. Heap and Stack

Rev316
I know a little about heap and stack. Why would I care where it gets put? When would I want it in the heap, and when would I want it in the stack?
Phenom
The stack is limited in an application. The Heap has no limit (Virtual memory space). The stack is also limited to the scope of the variable. The heap allows you to pass the structure around regardless of scope.
Romain Hippeau
This statement is wrong. Please don't ignore static memory. E.g. a `BTree btree;` statement in global (or namespace scope) creates the object in static memory, which can make a lot of sense, especially in memory-constrained environments (all those automatic memory managed languages like Java *cough* seemed to blind us..).
frunsi
One addition: from a memory perspective, e.g. an "application" object instance should be allocated in static memory: on app startup, the OS ensures that the static memory is available and allows the application to start or not.. the app object then can safely allocate more memory (and handle errors) and so on.. but sadly, people often forget this and ignore allocation errors or do it on their own. I'd just blame java -)
frunsi
+1  A: 

The first form creates the object on the heap whereas the second creates it on the stack.

The second from will be destroyed when the function is finished running. The first will remain alive until specifically deleted.

The second form is best if you want to only use the object in the current scope. You don't need to worry about getting rid of it because it'll be done for you. Also note that some libraries don't work if there classes are created on the stack.

If the object should outlive the function, the new form is a better option.

Winston Ewert
+12  A: 

Two differences:

  • they create the objects in different parts of the memory (heap vs stack)

  • the object lifetime is different: In the first case, the code manages the memory allocation explicitly, and it must also manage the deallocation explicitly (using delete/delete[]).

    In the second case, the object is automatically deallocated at the end of its enclosing scope (either a method, a nested block within a method, or a class)

Which one you uses depends mostly on the lifetime of the object (if it should outlive the method in which it is created or not).

ckarras
+1, I'd just like to add a first and simple rule of thumb: prefer automatic allocation, use explicit allocation when required, e.g. a BAD example: `void foo() { BTree* btree=new BTree; btree->DoSomething(); delete btree; }`
frunsi
If the object is declared in main, will it be automatically be deallocated when main exits for both methods?
Phenom
A heap-allocated object (using `new`) that isn't deleted before the program ends won't be "deallocated" per se. For instance, its destructor will not be called as the program is ending. However, the memory used by the object will be returned to the OS. There's no way that a program running under a modern OS can continue to consume memory after it has exited, no matter how badly it leaks.
Tyler McHenry
Why is it in the non-automatic case the integer variables get initialized to 0, but in the automatic case the integer variables are not initialized?
Phenom
Because it's defined this way in the standard, as an optimization for stack memory. See this answer to another question: http://stackoverflow.com/questions/1414215/initial-value-of-int-array-in-c/1414286#1414286.However I prefer working with the assumption that values are never initialized to 0, and instead assigning them in all cases (less risk of errors when working with both types of allocation within the same code)
ckarras
+1  A: 

The high-level distinction is object lifetime. For example, if you were writing a video game, you would allocate the objects corresponding to monsters on the heap, via new. That way, the monster's underlying object lives exactly as long as the monster does, which is unknowable when you write the program. When the player kills the monster, your code can destroy the monster object using delete.

A total-score counter, on the other hand, you would use the other form, because you know how long you want the counter to stay around (presumably, as long as the game is running!). By putting that form in the "global scope," outside of any function body, it would be allocated statically, as part of the program binary itself.

Finally, if you were computing the sum of an array, like this:

int mysum(int* arr, int len) {
  int sum = 0;
  for (int i = 0; i < len; ++i) { sum += arr[i] }
  return sum;
}

the sum variable is allocated on the stack, which is basically what you want: a temporary variable that you don't have to explicitly deallocate, and which is only around when that function is actually running.

Ben Karel
A: 

Another difference between these two form is the time when storage for those objects are allocated. The form BTree bTree; names static allocation whose allocation accomplishes at compile time -- i.e. the compiler will arrange memory space for this object in memory when running. While, the allocation for BTree *pbTree = new BTree, the alleged dynamic allocation -- performs at runtime -- i.e. the momory will be allocated only when the running program reach this point.

In this situation, the difference between static and dynamic allocation is not apparent. Consider the following circumstance where you need to allocate memory space for an integer array, but number of elements can be determined only at runtime, i.e. we can only know the exact memory space consumed by the array after the program begin to execute.

// in this function, we want to return a copy of the parameter array
int *array_cpy( int *arr, int num ){
    int *copy = new int[ num ];

    int i;
    for( i = 0; i < num; i++ ){
        copy[ i ] = arr[ i ];
    }

    return copy;
}

Here the definition int copy[ num ]; is not appropriate, one reason is for what I have stated above, the other is the lifetime of copy outlive the function. However, given VLA is permitted in recent language specification, the second reason is key to this problem.

Summer_More_More_Tea
+1  A: 

In choosing between whether you should stack or heap allocate memory, you need to dig a little into the differences between the two.

Yes, stack memory has the advantage of being deallocated automatically when it goes out of scope, although the same can be achieved with smart pointers and heap allocation. More important are the reasons behind why this happens.

Performance: Stack memory is cleaned up automatically because it involves the simply shift of a stack pointer when the memory goes out of scope. For this reason, allocation and deallocation of stack memory is much faster than heap memory.

Memory Lifetime: Heap allocated memory is available beyond the scope of the allocating function. Stack is not. Following from the reasoning around adjustment of the stack pointer above, once memory is deallocated, it is free and very likely to be overwritten for the next stack allocation.

In short, use stack memory when the allocation is temporary, particularly if you need to allocate repeatedly and performance is important. Use heap memory when the object needs to exist beyond the allocating method.

Phil Young