When should I use the new keyword in C++?
There is an important difference between the two.
Everything not allocated with new
behaves much like value types in C# (and people often say that those objects are allocated on the stack, which is probably the most common/obvious case, but not always true). More precisely, objects allocated without using new
have automatic storage duration
Everything allocated with new
is allocated on the heap, and a pointer to it is returned, exactly like reference types in C#.
Anything allocated on the stack has to have a constant size, determined at compile-time (the compiler has to set the stack pointer correctly, or if the object is a member of another class, it has to adjust the size of that other class). That's why arrays in C# are reference types. They have to be, because with reference types, we can decide at runtime how much memory to ask for. And the same applies here. Only arrays with constant size (a size that can be determined at compile-time) can be allocated with automatic storage duration (on the stack). Dynamically sized arrays have to be allocated on the heap, by calling new
.
(And that's where any similarity to C# stops)
Now, anything allocated on the stack has "automatic" storage duration (you can actually declare a variable as auto
, but this is the default if no other storage type is specified so the keyword isn't really used in practice, but this is where it comes from)
Automatic storage duration means exactly what it sounds like, the duration of the variable is handled automatically. By contrast, anything allocated on the heap has to be manually deleted by you. Here's an example:
void foo() {
bar b;
bar* b2 = new bar();
}
This function creates three values worth considering:
On line 1, it declares a variable b
of type bar
on the stack (automatic duration).
On line 2, it declares a bar
pointer b2
on the stack (automatic duration), and calls new, allocating a bar
object on the heap. (dynamic duration)
When the function returns, the following will happen:
First, b2
goes out of scope (order of destruction is always opposite of order of construction). But b2
is just a pointer, so nothing happens, the memory it occupies is simply freed. And importantly, the memory it points to (the bar
instance on the heap) is NOT touched. Only the pointer is freed, because only the pointer had automatic duration.
Second, b
goes out of scope, so since it has automatic duration, its destructor is called, and the memory is freed.
And the bar
instance on the heap? It's probably still there. No one bothered to delete it, so we've leaked memory.
From this example, we can see that anything with automatic duration is guaranteed to have its destructor called when it goes out of scope. That's useful. But anything allocated on the heap lasts as long as we need it to, and can be dynamically sized, as in the case of arrays. That is also useful. We can use that to manage our memory allocations. What if the Foo class allocated some memory on the heap in its constructor, and deleted that memory in its destructor. Then we could get the best of both worlds, safe memory allocations that are guaranteed to be freed again, but without the limitations of forcing everything to be on the stack.
And that is pretty much exactly how most C++ code works.
Look at the standard library's std::vector
for example. That is typically allocated on the stack, but can be dynamically sized and resized. And it does this by internally allocating memory on the heap as necessary. The user of the class never sees this, so there's no chance of leaking memory, or forgetting to clean up what you allocated.
This principle is called RAII (Resource Acquisition is Initialization), and it can be extended to any resource that must be acquired and released. (network sockets, files, database connections, synchronization locks). All of them can be acquired in the constructor, and released in the destructor, so you're guaranteed that all resources you acquire will get freed again.
As a general rule, never use new/delete directly from your high level code. Always wrap it in a class that can manage the memory for you, and which will ensure it gets freed again. (Yes, there may be exceptions to this rule. In particular, smart pointers require you to call new
directly, and pass the pointer to its constructor, which then takes over and ensures delete
is called correctly. But this is still a very important rule of thumb)
Which method should I use?
This is almost never determined by your typing preferences but by the context. If you need to keep the object across a few stacks or if it's too heavy for the stack you allocate it on the free store. Also, since you are allocating an object, you are also responsible for releasing the memory. Lookup the delete
operator.
To ease the burden of using free-store management people have invented stuff like auto_ptr
and unique_ptr
. I strongly recommend you take a look at these. They might even be of help to your typing issues ;-)
The short answer is: if you're a beginner in C++, you should never be using new
or delete
yourself.
Instead, you should use smart pointers such as std::unique_ptr
and std::make_unique
(or less often, std::shared_ptr
and std::make_shared
). That way, you don't have to worry nearly as much about memory leaks. And even if you're more advanced, best practice would usually be to encapsulate the custom way you're using new
and delete
into a small class (such as a custom smart pointer) that is dedicated just to object lifecycle issues.
Of course, behind the scenes, these smart pointers are still performing dynamic allocation and deallocation, so code using them would still have the associated runtime overhead. Other answers here have covered these issues, and how to make design decisions on when to use smart pointers versus just creating objects on the stack or incorporating them as direct members of an object, well enough that I won't repeat them. But my executive summary would be: don't use smart pointers or dynamic allocation until something forces you to.
Method 1 (using new
)
- Allocates memory for the object on the free store (This is frequently the same thing as the heap)
- Requires you to explicitly
delete
your object later. (If you don't delete it, you could create a memory leak) - Memory stays allocated until you
delete
it. (i.e. you couldreturn
an object that you created usingnew
) - The example in the question will leak memory unless the pointer is
delete
d; and it should always be deleted, regardless of which control path is taken, or if exceptions are thrown.
Method 2 (not using new
)
- Allocates memory for the object on the stack (where all local variables go) There is generally less memory available for the stack; if you allocate too many objects, you risk stack overflow.
- You won't need to
delete
it later. - Memory is no longer allocated when it goes out of scope. (i.e. you shouldn't
return
a pointer to an object on the stack)
As far as which one to use; you choose the method that works best for you, given the above constraints.
Some easy cases:
- If you don't want to worry about calling
delete
, (and the potential to cause memory leaks) you shouldn't usenew
. - If you'd like to return a pointer to your object from a function, you must use
new