So how does delete[] know how much to deallocate? When you allocate an array using new[]
, the runtime needs to track its size so that delete[]
can correctly free the allocated memory. The runtime adds a metadata before the actual array data.
1. How new[]
and delete[]
work internally
Step 1: Allocation with new[]
When you allocate an array:
int* arr = new int[5]; // Allocates space for 5 integers
- The runtime stores metadata (usually size information) before the actual array.
- The pointer returned by
new[]
is adjusted to point to the first array element.
Step 2: Deallocation with delete[]
When you call:
delete[] arr;
- The runtime looks at the hidden metadata stored before
arr
to determine how many elements were allocated. - It correctly calls the destructor (if needed) for each element.
- Finally, it frees the entire block of memory.
2. Where Is the Array Size Stored?
Common Implementations
Most C++ implementations store the array size just before the allocated memory block.
Example (assuming 4-byte metadata):
Memory Layout (simplified for new int[5])
-------------------------------------------------
| Metadata (size = 5) | arr[0] | arr[1] | ... | arr[4] |
-------------------------------------------------
↑
arr points here
When you call delete[] arr;
, it:
- Looks at the metadata before
arr
to get the size (5
in this case). - Calls the destructor for each element (if necessary).
- Frees the memory block.
3. Example: Tracking Array Size Manually
We can simulate this behavior manually:
#include <iostream>
void* myAlloc(size_t count) {
size_t* ptr = (size_t*)malloc(sizeof(size_t) + count * sizeof(int));
*ptr = count; // Store size at the beginning
return (void*)(ptr + 1); // Return the address after metadata
}
void myDealloc(void* mem) {
size_t* ptr = ((size_t*)mem) - 1; // Access metadata
std::cout << "Freeing array of size: " << *ptr << std::endl;
free(ptr); // Free the entire allocated block
}
int main() {
int* arr = (int*)myAlloc(5);
myDealloc(arr);
return 0;
}
✅ Output:
Freeing array of size: 5
This shows how delete[]
can determine the number of elements.
4. Does delete[]
Call Destructors?
Yes! When you use new[]
for an array of objects, delete[]
ensures that all destructors are called.
Example:
#include <iostream>
class Test {
public:
Test() { std::cout << "Constructor\n"; }
~Test() { std::cout << "Destructor\n"; }
};
int main() {
Test* arr = new Test[3];
delete[] arr;
}
✅ Output:
Constructor
Constructor
Constructor
Destructor
Destructor
Destructor
Why? Because delete[]
retrieves the stored array size and calls the destructor for each element.
5. Summary
Action | How It Works |
---|---|
new[] allocation | Stores array size before the returned pointer |
Pointer returned | Points to the first element, not the metadata |
delete[] behavior | Reads stored size, calls destructors (if needed), then frees memory |
Raw pointers | delete without [] on arrays causes memory leaks |
Summary:
✔ delete[]
knows how much to deallocate because new[]
stores hidden metadata before the array.
✔ The compiler/runtime retrieves this metadata to correctly free the memory and call destructors.
✔ Never use delete
instead of delete[]
for arrays, or you’ll cause undefined behavior!