Dynamic Memory Allocation in C++


Dynamic Memory Allocation in C++ Interview with follow-up questions

1. What is dynamic memory allocation in C++?

Dynamic memory allocation is the process of requesting memory from the operating system at runtime, as opposed to having the compiler reserve it at compile time. In C++, this memory comes from the heap (also called the free store).

Why it is needed:

  • The size of data is not always known at compile time (e.g., reading a file of unknown length, building a variable-size container).
  • Objects must outlive the scope in which they were created.
  • Very large allocations would overflow the stack.

The C++ mechanisms:

Mechanism When to use
new / delete Low-level; required when interfacing with legacy APIs or implementing containers
new[] / delete[] Arrays on the heap (prefer std::vector instead)
std::make_unique (C++14) Preferred way to heap-allocate a single object with sole ownership
std::make_shared (C++14) Preferred way to heap-allocate with shared ownership
std::vector, std::string, etc. Manage their own heap memory; use these for collections

Modern C++ guidance: raw new and delete should rarely appear in application code. Prefer RAII types and smart pointers that own their heap memory and release it automatically. Reserve raw allocation for library internals or performance-critical custom allocators.

Failure behavior: by default, new throws std::bad_alloc if the system cannot satisfy the request. The non-throwing variant new(std::nothrow) returns nullptr instead, which is useful in embedded or low-memory environments where exceptions are disabled.

↑ Back to top

Follow-up 1

Can you explain the difference between static and dynamic memory allocation?

Static memory allocation refers to the allocation of memory at compile time. The size and lifetime of the allocated memory are determined during the compilation process. Static memory allocation is done using static variables, global variables, and arrays.

Dynamic memory allocation, on the other hand, refers to the allocation of memory at runtime. The size and lifetime of the allocated memory are determined during program execution. Dynamic memory allocation is done using pointers and the new operator in C++.

Follow-up 2

What are the advantages of dynamic memory allocation?

Dynamic memory allocation offers several advantages:

  1. Flexibility: Dynamic memory allocation allows programs to allocate memory as needed, enabling them to handle varying amounts of data.

  2. Efficiency: Dynamic memory allocation can help optimize memory usage by allocating memory only when required and freeing it when no longer needed.

  3. Resource management: Dynamic memory allocation allows programs to manage limited resources effectively by allocating and deallocating memory as needed.

  4. Data structures: Dynamic memory allocation is essential for implementing dynamic data structures such as linked lists, trees, and graphs.

Follow-up 3

What are the new and delete operators in C++?

In C++, the new operator is used for dynamic memory allocation. It is used to allocate memory for objects or arrays of objects on the heap. The new operator returns a pointer to the allocated memory.

Example:

int* ptr = new int; // allocate memory for an integer

The delete operator is used to deallocate memory that was previously allocated using the new operator. It frees the memory and makes it available for reuse.

Example:

int* ptr = new int; // allocate memory
// ... do something with ptr

delete ptr; // deallocate memory

Note: It is important to properly deallocate memory using the delete operator to avoid memory leaks.

Follow-up 4

How can memory leaks occur in dynamic memory allocation?

Memory leaks can occur in dynamic memory allocation when memory is allocated but not properly deallocated. This can happen if the delete operator is not called for every new operator used to allocate memory. If memory leaks occur, the allocated memory is not freed and becomes unavailable for reuse, leading to a waste of memory resources.

Example:

int* ptr = new int; // allocate memory
// ... do something with ptr

// delete operator is not called

To prevent memory leaks, it is important to always deallocate memory using the delete operator when it is no longer needed.

2. How do you allocate memory dynamically for an array in C++?

The raw-pointer way is to use new[] and pair it with delete[]:

int* arr = new int[10];   // allocate array of 10 ints on the heap
arr[0] = 42;
delete[] arr;             // must use delete[], not delete
arr = nullptr;            // good habit: avoid dangling pointer

Using delete instead of delete[] is undefined behavior — always match new[] with delete[].

The modern C++ approach — prefer std::vector:

#include 

std::vector arr(10);   // heap-allocated, size known at runtime
arr[0] = 42;
// automatically freed when arr goes out of scope — no delete needed

std::vector handles allocation, reallocation on growth, bounds-checked access via .at(), and cleanup — making raw new[] unnecessary in almost all application code.

When you need a fixed-size heap array and sole ownership, use std::unique_ptr:

#include 

auto arr = std::make_unique(10);  // C++14
arr[0] = 42;
// automatically freed when arr goes out of scope

std::unique_ptr correctly calls delete[] in its destructor and supports operator[], making it a safe drop-in for raw new[] when you truly need a plain array rather than a resizable container.

Runtime-size 2D arrays: use std::vector> or a flat std::vector with manual index arithmetic for best compatibility and safety.

↑ Back to top

Follow-up 1

What happens if dynamic memory allocation fails?

If dynamic memory allocation fails, the 'new' operator throws a 'std::bad_alloc' exception. You can catch this exception and handle the failure gracefully.

Follow-up 2

How can you prevent memory leaks when working with dynamic arrays?

To prevent memory leaks when working with dynamic arrays, you should always remember to deallocate the memory using the 'delete[]' operator. Here's an example:

int* dynamicArray = new int[5];
// Use the dynamic array

// Deallocate the memory
delete[] dynamicArray;

Follow-up 3

Can you explain the concept of array decay in the context of dynamic arrays?

In C++, when a dynamic array is passed to a function, it decays into a pointer to its first element. This means that the size of the array is lost, and the function can only access the elements using pointer arithmetic. Here's an example:

void printArray(int* array, int size) {
    for (int i = 0; i < size; i++) {
        cout << array[i] << " ";
    }
}

int* dynamicArray = new int[5];
// Initialize and use the dynamic array

printArray(dynamicArray, 5);

3. What is the role of the 'new' operator in C++?

The new operator allocates memory on the heap at runtime and returns a typed pointer to the allocated region. It performs two operations in one expression:

  1. Allocates memory by calling operator new (which ultimately calls malloc or a custom allocator).
  2. Constructs the object in that memory by calling the appropriate constructor.
int* p = new int(42);          // allocate one int, initialize to 42
MyClass* obj = new MyClass();  // allocate + default-construct
int* arr = new int[10]{};      // allocate array of 10 ints, zero-initialized

Failure behavior: if allocation fails, new throws std::bad_alloc by default. The nothrow variant returns nullptr instead:

int* p = new(std::nothrow) int(42);
if (!p) { /* handle allocation failure */ }

Placement new: a third form constructs an object in already-allocated memory (used in custom allocators, embedded systems, and std::optional internals):

alignas(MyClass) std::byte buf[sizeof(MyClass)];
MyClass* obj = new(buf) MyClass();  // construct in-place, no heap allocation
obj->~MyClass();                    // must manually destroy when done

Modern C++ guidance: in application code, avoid calling new directly. Use std::make_unique() or std::make_shared() instead — they allocate and construct in one step, return a safe owning smart pointer, and are exception-safe even if the constructor throws. Direct new should be reserved for low-level library code or custom memory management.

auto p = std::make_unique();  // preferred over: MyClass* p = new MyClass();
↑ Back to top

Follow-up 1

What is the difference between 'new' and 'malloc'?

The 'new' operator is used to allocate memory for objects and automatically calls the constructor to initialize the object. On the other hand, 'malloc' is a function from the C standard library that is used to allocate memory for a specified number of bytes. It does not call the constructor, so the allocated memory is uninitialized.

Follow-up 2

What happens if 'new' fails to allocate memory?

If the 'new' operator fails to allocate memory, it throws a 'std::bad_alloc' exception. This exception can be caught using a try-catch block, and appropriate error handling can be performed.

Follow-up 3

Can you explain the process of overloading the 'new' operator?

Yes, the 'new' operator can be overloaded in C++. Overloading the 'new' operator allows you to customize the memory allocation process. To overload the 'new' operator, you need to define a global or a class-specific 'new' operator function. This function should have the same name as the 'new' operator and should return a pointer to the allocated memory. You can then define your own memory allocation strategy inside this function.

4. What is the role of the 'delete' operator in C++?

The delete operator deallocates heap memory that was previously allocated with new and destroys the object. It performs two operations:

  1. Calls the destructor of the object, releasing any resources it owns.
  2. Frees the underlying memory by calling operator delete.
int* p = new int(42);
delete p;       // destroys the int and frees the memory
p = nullptr;    // good practice: prevents use-after-free bugs

MyClass* obj = new MyClass();
delete obj;     // calls ~MyClass(), then frees memory

delete[] for arrays: memory allocated with new[] must be freed with delete[]. Using plain delete on an array is undefined behavior.

int* arr = new int[10];
delete[] arr;   // correct — matches new[]

Common pitfalls:

  • Double delete: calling delete twice on the same pointer is undefined behavior. Setting the pointer to nullptr after deletion makes a second delete a safe no-op.
  • Mismatched operators: always pair new with delete and new[] with delete[].
  • Deleting a nullptr: safe and well-defined — delete nullptr does nothing.

Modern C++ guidance: in application code, avoid raw delete entirely. Smart pointers (std::unique_ptr, std::shared_ptr) call delete (or a custom deleter) automatically in their destructor, eliminating the risk of forgotten or double deletions. If you find yourself writing delete, it is usually a sign that the surrounding code should be using RAII or a standard container instead.

↑ Back to top

Follow-up 1

What is the difference between 'delete' and 'free'?

The 'delete' operator is used to deallocate memory for objects created using the 'new' operator, while the 'free' function is used to deallocate memory allocated using the 'malloc' function. The 'delete' operator also calls the destructor of the object being deleted, while 'free' does not. Additionally, 'delete' is a keyword in C++, while 'free' is a function in the C standard library.

Follow-up 2

What happens if 'delete' is used on a pointer that has already been deleted?

If 'delete' is used on a pointer that has already been deleted, it will result in undefined behavior. This is because 'delete' assumes that the pointer being deleted is valid and has not been previously deleted. It is important to ensure that a pointer is not deleted more than once to avoid such issues.

Follow-up 3

Can you explain the process of overloading the 'delete' operator?

Yes, the 'delete' operator can be overloaded in C++. Overloading the 'delete' operator allows you to customize the deallocation process for objects created using 'new'. To overload the 'delete' operator, you need to define a global or member function with the following signature:

void operator delete(void* ptr);

This function will be called when 'delete' is used to deallocate memory for an object. Within the overloaded 'delete' function, you can implement your own deallocation logic, such as releasing additional resources or performing custom cleanup operations.

5. What are memory leaks and how can they be prevented in C++?

A memory leak occurs when heap memory is allocated but never deallocated, causing the program to permanently lose access to those bytes. Over time, leaked memory accumulates, can exhaust available RAM, and degrades performance — particularly critical in long-running servers and embedded systems.

Common causes:

  • Calling new without a matching delete (including when an exception is thrown between the two).
  • Losing the last pointer to a heap object before deleting it.
  • Circular shared_ptr references — two objects each hold a shared_ptr to the other, so the reference count never reaches zero.
  • Forgetting to call delete[] for memory allocated with new[].

Prevention strategies:

  1. Prefer RAII containers and types. std::vector, std::string, and other standard containers manage their own memory — no manual delete needed.

  2. Use std::unique_ptr by default. It deletes its object when it goes out of scope, even if an exception is thrown. Create with std::make_unique() (C++14):

    auto p = std::make_unique();  // freed automatically
    
  3. Use std::shared_ptr for shared ownership, created with std::make_shared(). The object is deleted when the last owning pointer is destroyed.

  4. Break cyclic shared_ptr references with std::weak_ptr. A weak_ptr observes the object without incrementing the reference count, allowing the cycle to be broken.

  5. Follow the Rule of Zero. If your class only holds smart pointers and standard containers as members, you don't need to write a destructor, copy constructor, or copy-assignment operator — the compiler-generated defaults handle cleanup correctly.

  6. Use detection tools during development:

    • AddressSanitizer (ASan) — compile with -fsanitize=address (Clang/GCC); catches leaks, use-after-free, and more.
    • Valgrind (valgrind --leak-check=full) — detailed leak reports on Linux.
    • LeakSanitizer (LSan) — lightweight leak detection, often bundled with ASan.
  7. Avoid raw owning pointers in application code. If you see a raw new without an immediate assignment to a smart pointer, treat it as a code smell.

↑ Back to top

Follow-up 1

What tools can be used to detect memory leaks in C++?

There are several tools that can be used to detect memory leaks in C++:

  1. Valgrind: Valgrind is a popular memory profiling tool that can detect memory leaks, as well as other memory errors like invalid memory access and uninitialized variables.
  2. AddressSanitizer: AddressSanitizer is a memory error detector tool built into the Clang and GCC compilers. It can detect memory leaks, buffer overflows, and other memory errors.
  3. Visual Leak Detector: Visual Leak Detector is a free memory leak detection tool for Windows that works with Visual C++.
  4. Purify: Purify is a commercial memory debugging tool that can detect memory leaks, buffer overflows, and other memory errors.
  5. LeakTracer: LeakTracer is a lightweight memory leak detection tool for C++ that can be easily integrated into your codebase.

Follow-up 2

What is the impact of memory leaks on a program's performance?

Memory leaks can have a significant impact on a program's performance. When memory leaks occur, the program continues to allocate memory without releasing it, leading to a gradual increase in memory usage. As a result, the program may consume excessive amounts of memory, causing it to slow down or even crash due to running out of memory.

In addition to the direct impact on memory usage, memory leaks can also lead to other performance issues. For example, if memory leaks occur in a loop or a frequently called function, the program may experience a slowdown due to the repeated allocation of memory without proper deallocation.

Furthermore, memory leaks can also cause fragmentation of the memory heap, making it harder for the program to find contiguous blocks of memory for allocation, which can further degrade performance.

Follow-up 3

Can you give an example of a situation that could lead to a memory leak?

Sure! Here's an example of a situation that could lead to a memory leak in C++:

void createMemoryLeak() {
    int* ptr = new int(5);
    // Do something with ptr, but forget to delete it
}

int main() {
    createMemoryLeak();
    // The memory allocated in createMemoryLeak() is leaked
    return 0;
}

In this example, the createMemoryLeak() function dynamically allocates an int using the new keyword, but forgets to deallocate it using the delete keyword. As a result, the memory allocated for the int is leaked and cannot be reclaimed by the program. If this code is executed multiple times, it will result in a memory leak and a waste of memory resources.

Live mock interview

Mock interview: Dynamic Memory Allocation in C++

Intermediate ~5 min Your own free AI key

Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.