Back to C++
2026-01-158 min read

C++ Memory Management: new and delete

Learn C++ Memory Management: new and delete step by step with clear examples and exercises.

Why This Matters

Welcome to a full guide on C++ Memory Management using new and delete. These operators are essential for dynamically allocating and deallocating memory during runtime, making them crucial for creating flexible, efficient, and well-optimized programs.

Understanding new and delete can help you:

  1. Write more efficient code by avoiding unnecessary memory allocation and deallocation.
  2. Prepare for interviews and exams by demonstrating a strong understanding of C++ memory management concepts.
  3. Debug real-world programming issues related to memory leaks, segmentation faults, and other memory-related errors.
  4. Create dynamic data structures like arrays, linked lists, trees, and more during runtime.
  5. Use placement new for custom allocators or memory pools when working with complex data structures.
  6. Implement exception safety by using custom allocators that throw exceptions on failure.
  7. Optimize memory usage in large-scale applications with techniques like memory compaction.

Prerequisites

To fully grasp this lesson, you should be familiar with the following topics:

  1. Basic C++ syntax (variables, constants, operators, control structures)
  2. Data types (int, char, float, double, etc.)
  3. Arrays and pointers
  4. Classes and objects
  5. Basic understanding of memory management concepts in C++, such as stack and heap memory.
  6. Exception handling (optional but recommended for understanding exception safety)

Core Concept

Allocating Memory with new

The new operator is used to dynamically allocate memory for a variable during runtime. The general syntax for using new is:

type *ptr = new type;

Here, type represents the data type of the memory you want to allocate, and ptr is a pointer that stores the address of the allocated memory. For example:

int *pInt = new int; // Allocates memory for an integer
char *pChar = new char[10]; // Allocates memory for 10 characters
MyClass *pObj = new MyClass(); // Allocates memory for an instance of the MyClass class

Initializing Memory with new

If you want to initialize the memory when allocating it, you can use the following syntax:

type *ptr = new type(initial_value);

For example:

int *pInt = new int(42); // Allocates memory for an integer and initializes it to 42
char *pChar = new char[10]{'a', 'b', 'c', ...}; // Allocates memory for 10 characters and initializes them
MyClass *pObj = new MyClass(initial_values); // Allocates memory for an instance of the MyClass class and initializes it with the given initial values

Deallocating Memory with delete

Once you no longer need the dynamically allocated memory, use the delete operator to free it. The general syntax for using delete is:

delete ptr;

Here, ptr is the pointer that was used to allocate the memory initially. For example:

int *pInt = new int(42);
// ... use pInt ...
delete pInt; // Frees the memory allocated for pInt

Array Allocation with new[] and Deallocation with delete[]

When allocating an array using new, you should use square brackets:

type *ptr = new type[array_size];

To deallocate the memory, use delete[] instead of just delete:

delete [] ptr;

For example:

int *pIntArray = new int[10]; // Allocates memory for an array of 10 integers
// ... use pIntArray ...
delete [] pIntArray; // Frees the memory allocated for pIntArray and the entire array

Using Placement new with a Custom Allocator

You can also use placement new to create an object at a specific location in memory, which is useful when working with custom allocators or memory pools. The syntax for using placement new is:

::new(memory_location) type;

For example:

void *mem = malloc(sizeof(MyClass));
::new(mem) MyClass(); // Creates an instance of MyClass at the given memory location

Common Pitfalls with new and delete

  1. Forgetting to deallocate memory: Failing to free dynamically allocated memory can lead to a memory leak, which causes your program to consume more resources than necessary.
  2. Double-freeing memory: If you try to delete memory that has already been freed, it may cause undefined behavior or a segmentation fault.
  3. Not initializing pointers before using them: Using an uninitialized pointer can lead to unexpected results and hard-to-debug issues. Always set pointers to nullptr before allocating memory with new.
  4. Using the wrong deallocator: Remember to use delete[] for arrays and delete for individual objects.
  5. Leaking memory in loops: If you allocate memory inside a loop and forget to deallocate it after each iteration, your program will continue to consume more memory with each loop cycle, eventually leading to a crash or other issues.
  6. Memory fragmentation: Over time, the heap can become fragmented as memory is allocated and deallocated, making it difficult to find contiguous blocks of memory for larger allocations. Techniques like memory compaction can help mitigate this issue.
  7. Performance overhead: Dynamic memory allocation with new and delete can have a performance overhead due to the need to manage memory during runtime. In some cases, using statically-sized arrays or containers from the Standard Template Library (STL) may be more efficient.
  8. Lack of exception safety: By default, both new and delete do not throw exceptions when an allocation or deallocation fails. To handle such failures, you can use placement new with a custom allocator that throws exceptions on failure.
  9. Not handling exceptions properly: When using custom allocators with exception safety, it's important to ensure that any exceptions thrown during memory allocation or deallocation are propagated correctly to avoid memory leaks or other issues.
  10. Inconsistent use of new and malloc/free: Mixing new and malloc/free can lead to confusion, inconsistencies, and potential memory-related errors. It's recommended to stick with new for C++ memory management whenever possible.

Worked Example

Let's create a simple program that dynamically allocates an array of integers, initializes them with user input, and then deallocates the memory:

#include <iostream>
using namespace std;

int main() {
int *arr;
int size;

cout << "Enter the size of the array: ";
cin >> size;

arr = new int[size]; // Allocate memory for an array of size integers

cout << "Enter the elements of the array:\n";
for (int i = 0; i < size; ++i) {
cin >> arr[i];
}

cout << "Your array is:\n";
for (int i = 0; i < size; ++i) {
cout << arr[i] << ' ';
}
cout << '\n';

delete [] arr; // Deallocate the memory allocated for arr and the entire array

return 0;
}

Common Mistakes

  1. Forgetting to initialize pointers before using them: Always set pointers to nullptr before allocating memory with new.
  2. Double-freeing memory: Check if a pointer is nullptr before attempting to deallocate it.
  3. Using the wrong deallocator: Remember to use delete[] for arrays and delete for individual objects.
  4. Leaking memory in loops: Deallocate memory after each iteration of a loop that allocates memory dynamically.
  5. Memory fragmentation: Use techniques like memory compaction or custom allocators to minimize memory fragmentation.
  6. Performance overhead: Consider using statically-sized arrays or containers from the Standard Template Library (STL) for better performance in some cases.
  7. Lack of exception safety: Implement custom exception handling with a custom allocator that throws exceptions on failure.
  8. Inconsistent use of new and malloc/free: Stick with new for C++ memory management whenever possible to avoid confusion and potential errors.

Practice Questions

  1. Write a program that dynamically allocates an array of char and initializes it with user input, then deallocates the memory.
  2. Given the following code:
int *pInt = new int[5];
for (int i = 0; i < 5; ++i) {
pInt[i] = i * 2;
}
// ... more code ...
delete [] pInt;

What is the value of pInt[3] after the loop but before the memory is deallocated?

  1. Write a program that dynamically allocates an array of double, initializes it with user input, and then finds the maximum value in the array.
  2. Implement a custom allocator for an STL container (e.g., vector or list) that uses a memory pool to reduce memory fragmentation.
  3. Write a function that checks if a given pointer is valid (i.e., not nullptr and points to allocated memory).
  4. Given the following code:
int *pInt = new int(42);
MyClass *pObj = new MyClass();
// ... more code ...
delete pInt;
delete pObj;

What is the order in which the objects pointed to by pInt and pObj are destroyed when they are deallocated?

FAQ

1. Why should I use new and delete instead of statically-sized arrays?

Using dynamic memory allocation allows you to create data structures of varying sizes at runtime, which can be more flexible and efficient for certain applications. Statically-sized arrays have a fixed size that must be known at compile time, whereas dynamically-allocated memory can be resized as needed during program execution.

2. What happens if I forget to deallocate dynamically allocated memory?

If you forget to deallocate dynamically allocated memory, it will not be freed and may cause a memory leak, which consumes more resources than necessary and can lead to performance issues or crashes in your program.

3. Can I use new and delete with objects (classes) as well?

Yes! You can use new to create instances of classes dynamically and delete to destroy them. To do this, simply replace the data type in the new and delete statements with the name of your class:

MyClass *pObj = new MyClass(); // Allocate memory for an instance of MyClass
// ... use pObj ...
delete pObj; // Deallocate the memory allocated for pObj and destroy the instance

4. What is the difference between new[] and new?

new is used to create a single object, while new[] is used to create an array of objects. The corresponding deallocators are delete for a single object and delete[] for an array.

5. How can I avoid memory fragmentation when using new and delete?

Techniques like memory compaction, custom allocators, and memory pools can help mitigate memory fragmentation when using dynamic memory allocation with new and delete.

6. What is placement new and how can it be used?

placement new is a feature that allows you to create an object at a specific location in memory, which is useful when working with custom allocators or memory pools. The syntax for using placement new is:

::new(memory_location) type;

For example:

void *mem = malloc(sizeof(MyClass));
::new(mem) MyClass(); // Creates an instance of MyClass at the given memory location

7. What is the order of destruction for objects created with new[] and deleted with delete[]?

When you use delete [] to deallocate an array created with new [], the destructors (if any) for the objects in the array are called in reverse order of their construction, from last to first. This is known as reverse iteration order destruction.

8. How can I implement custom exception handling with new and delete?

To implement custom exception handling with new and delete, you can create a custom allocator that throws exceptions on failure. Here's an example of how to do this for an STL vector:

#include
#include
#include

class CustomAllocator : public std::allocator {
public:
CustomAllocator() throw() {}
C++ Memory Management: new and delete | C++ | XQA Learn