4

I'm learning C++ at the moment and there's something I'm unclear on.

If I create a function that allocates memory for an array of some type and then returns the newly-created pointer, given that the pointer is just a memory address, will a corresponding delete statement clean up all of the allocated memory correctly, or will only the first element be deallocated, creating a memory leak with the remainder of the array? If it is cleaned up correctly, how does C++ know what to deallocate, given my presumed loss of context inherent in the return type?

int* AllocateSomething()
{
    int *arr = new int[100];
    // fill the array with something...
    return arr;
}

int main()
{
    int* p = AllocateSomething();
    delete p; // what will this do?
    delete[] p; // how would this know how much memory to delete?
}

Normally I would just write some test code to figure out the answer to something but given that accessing unallocated memory results in undefined behaviour, I'm not exactly sure what I would test for.

Nathan Ridley
  • 33,766
  • 35
  • 123
  • 197
  • possible duplicate of [Is delete\[\] equal to delete?](http://stackoverflow.com/questions/1553382/is-delete-equal-to-delete) – Amadeus Feb 21 '15 at 02:01
  • I can see how you would see it as a duplicate, but the context of my question is slightly different. I'm trying to understand mainly how the compiler even knows what to delete. The other question is then, I guess, a subset of my question. – Nathan Ridley Feb 21 '15 at 02:09
  • 1
    I think what everyone seems to be missing here, is that the question is more about the curiosity of how does the runtime know what to delete. And the answer is that the standard allocator keeps track of newed/malloced memory regions in two categories: non-array and array allocations. If you really want to familiarize yourself, try writing a simple allocator class yourself that internally works with a large chunk of total memory and divides it up for client code. Then you will understand the kinds of information needs to be tracked, and what the performance/safety/complexity implications are. – Preet Kukreti Feb 21 '15 at 02:54
  • 1
    This explains it well. http://stackoverflow.com/questions/197675/how-does-delete-know-the-size-of-the-operand-array – Jovibor Feb 21 '15 at 03:21

5 Answers5

3

You must use delete[] p the other one leads to undefined behaviour. Typically the compiler stores some number before the array to know how big it is. Depends on the implementation. Also main should return int, but that is not that serious.

EDIT: since you are interested about possible implementation here's the dissasembly (gcc 4.8, linux x86_64):

(gdb) l AllocateSomething
1       int* AllocateSomething()
2       {
3         int *arr1 = new int[100];
4         int *arr2 = new int[200];
5         int *arr3 = new int[300];
6         int *arr4 = new int[400];
7         arr1[0] = arr2[0] = arr3[0] = arr4[0] = ~0;
8
9
10
(gdb) x/20 arr1-8
0x601ff0:       0       0       0       0
0x602000:       0       0       417     0
0x602010:       -1      0       0       0
0x602020:       0       0       0       0
0x602030:       0       0       0       0
(gdb) x/20 arr2-8
0x602190:       0       0       0       0
0x6021a0:       0       0       817     0
0x6021b0:       -1      0       0       0
0x6021c0:       0       0       0       0
0x6021d0:       0       0       0       0
(gdb) x/20 arr3-8
0x6024c0:       0       0       0       0
0x6024d0:       0       0       1217    0
0x6024e0:       -1      0       0       0
0x6024f0:       0       0       0       0
0x602500:       0       0       0       0
(gdb) x/20 arr4-8
0x602980:       0       0       0       0
0x602990:       0       0       1617    0
0x6029a0:       -1      0       0       0
0x6029b0:       0       0       0       0
0x6029c0:       0       0       0       0

Memory dumps for each array. -1 marks start of the array. I'm printing from 8th element (4 bytes ints) before the start. You can clearly see the size of the array (sizeof (int) * the constant) + 17 auxiliary bytes stored in a word (8 bytes) before the array.

Miroslav Franc
  • 1,282
  • 12
  • 13
  • Awesome, thanks, the storage of the array size in memory is what I wasn't sure about. – Nathan Ridley Feb 21 '15 at 02:03
  • @NathanRidley Whatever you store in memory was placed there sooner or later by a `malloc`. [Outline of memory how looks then](http://web.archive.org/web/20070306235934im_/http://i144.photobucket.com/albums/r180/taossa/arraymem1.jpg). By calling `delete[]` you're saying go to each element (in the block determined by pointer to first object and malloc header) and call a destructor on the object you find in there. `delete` however doesn't do that. Depending on the compiler you use, some will detect this and some won't. Compiler doesn't know if it is an array or not, especially for dynam. alloc. – ljetibo Feb 21 '15 at 02:25
1

Whenever you are dynamically allocating arrays on the heap using 'new' (such as int[], bool[], etc.) you want to delete memory using delete[], otherwise as pointed out in Miroslav's answer, you will get undefined behaviour using just the 'delete' form of the operator.

If you are using C++11 or later I invite you to check out the new smart pointer features of the language such as std::unique_ptr which deals with freeing memory for you (esentially RAII).

Anthony Calandra
  • 1,429
  • 2
  • 11
  • 17
  • Could you elaborate on my question with regards to the loss of context I was concerned about? If I'm returning just a pointer, how does the compiler in the calling function know how much memory to delete? Miroslav (in the other answer) says that the compiler typically stores some number in memory so that it knows how much to delete later on. Does this sound correct? – Nathan Ridley Feb 21 '15 at 02:07
  • @NathanRidley I don't write compilers so I don't know what typically happens but I would assume when memory is allocated for the array the size of the memory block is saved for this reason otherwise we would have memory leaks. – Anthony Calandra Feb 21 '15 at 02:14
1

delete p; This is wrong since you allocated an array with new operator.-> first
delete[] p; This is right. -> second

When you run a C++ program there are two types of memory, one is stack memory and another is heap memory. When you use operator new system allocating memory in heap of the memory and this memory allocation is keeping in context of execution process so it is called dynamically allocated memory. Context info is not keeping in function but process wise, since it is a resource. So even after return from function, process knows its resources in hand so by using delete[] operator system can clean up allocated memory. The first pointer of your array may offset with array size depends on implementation and that will play in time of deletion of memory in case of arrays.

Steephen
  • 14,645
  • 7
  • 40
  • 47
1

When you create an array on the heap using new, you are returning a pointer to the first element in the array. So in your example, when you write delete p, you are saying delete the first element in the array. However, when you say delete [] p, you are saying delete the whole thing.

ChrisD
  • 674
  • 6
  • 15
1

If it is cleaned up correctly, how does C++ know what to deallocate

How does delete[] "know" the size of the operand array?

When you allocate memory on the heap, your allocator will keep track of how much memory you have allocated. This is usually stored in a "head" segment just before the memory that you get allocated. That way when it's time to free the memory, the de-allocator knows exactly how much memory to free.

Community
  • 1
  • 1
Jovibor
  • 759
  • 2
  • 6
  • 16