12

I have a question regarding deleting an array from heap memory. In a book and on this blog and in other resources such as this one, I read that for removing an array from the heap we must use the [] after the delete keyword so that if we do not use [] we will have leak memory.

for example, consider the code below.

//constructing array
int *s = new int[10];


// deleting array from heap
delete [] s;

I tested this little program in Linux by using the valgrind package to check how much memory leaks we have which are caused by bad coding. By below command in Linux, I saw that everything is alright

sudo valgrind --leak-check=full ./<path_to_exe_file>

this is the output of the Linux command

 ==4565== HEAP SUMMARY:
 ==4565==     in use at exit: 0 bytes in 0 blocks
 ==4565==   total heap usage: 1 allocs, 1 frees, 40 bytes allocated
 ==4565== 
 ==4565== All heap blocks were freed -- no leaks are possible

However, My question arose when I tried to use the delete without using []. The output from valgrind shows that all heap memory has been freed. Is this correct? or valgrind didn't realize the heap wasn't freed and some part of the array is still in there!!? If valgrind cannot detect this kind of memory leak, is there any other package that can detect this?

Saeed Masoomi
  • 1,703
  • 1
  • 19
  • 33
  • `int *s = new int[10]; delete s;` gives undefined behaviour. The form of operator `delete` needs to match the form of operator `new`. One possible manifestation of undefined behaviour is running as you expect, such as you are seeing. With another compiler, it may run differently, or not at all. – Peter Nov 04 '17 at 13:40
  • `delete` what you `new`-ed and `delete[]` what you `new[]`-ed. Or even better use smart pointers instead. – Ron Nov 04 '17 at 13:47
  • 1
    Replace `int` by `std::vector` or `std::string` to see the expected leak in your UB program. – Jarod42 Nov 04 '17 at 13:48
  • Spaces in expressions make no difference to a compiler, only to humans. – Ron Nov 04 '17 at 13:54
  • It's so weird with using `std::vector` if I use `[]`, some part of memory has been lost. @Jarod42 – Saeed Masoomi Nov 04 '17 at 13:55
  • Thanks, the question is not about space @Ron – Saeed Masoomi Nov 04 '17 at 13:56

2 Answers2

7

Calling delete on an array without using [] results in Undefined Behaviour. The Undefined Behaviour might be that the array is correctly deleted, which appears to be what you observed. You can't rely on this, however.

  • So answer of my question thank to your post and others comments is that there is leaked memory but `valgrind` couldn't detect that :) – Saeed Masoomi Nov 04 '17 at 14:01
  • 2
    No, there is no leaked memory - you just got lucky. –  Nov 04 '17 at 14:02
  • Wow I didn't know this might be happen – Saeed Masoomi Nov 04 '17 at 14:04
  • @saeedmasoomi Undefined behaviour often results in desired behaviour. For example, if you go with `int* get_invalid_pointer(){int a = 3; return &a;}` and call it like `int* b = get_invalid_pointer(); cout << *b << endl;`, this will actually most likely print "3". If you put some code between getting `int* b =...` and the printing, there is a good chance it won't work anymore. That's undefined behaviour for you. The worst situation with it is when the code seems to work just fine. – Aziuth Nov 05 '17 at 10:39
  • The worst is when it `seems` to work while testing. Then fails unexpectedly in production. – Martin York Oct 24 '20 at 20:37
5

Martin Broadhurst has already given the correct language-lawyer answer. I'm going to give the technical detail answer:

The point about using delete[] over delete is, that there is no way for the delete operator to know whether the passed pointer points to an array or to a single object. As such, delete only deletes a single object, while delete[] invokes some additional magic to recover the size of the array, and proceeds to delete all the elements.

Now deleting consists of two distinct parts:

  1. The objects must be destroyed by calling destructors. For an array, this means one destructor call for each array element.

  2. The memory that was used must be marked as free so that it may be reused. This is the job of the global operator delete() in C++. Since arrays are stored consecutively, this is a single call for the entire array.

valgrind is only concerned about memory. As such, it hooks memory allocating functions like malloc(), free(), operator new(), and operator delete().

What happens when you call delete instead of delete[] is, that the first object is destructed, and the pointer is passed on to operator delete(). operator delete() does not know about the object(s) that were stored inside the memory region, they are destroyed already anyway, so it will successfully mark the memory region as free. valgrind sees this operator delete() call, and is happy since all memory is free for reuse. However, your code failed to destruct all but the first array elements properly. And this is bad.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • a few days ago I wrote a program. when I run this program it takes 2 minutes to complete task!! but when I use `valgrind` package, the output is ready in just 3 seconds and I guessed that the `valgrind` just takes a shallow look at the code! Thank you for your answer it is really helpful for me. – Saeed Masoomi Nov 11 '17 at 18:27
  • @saeedmasoomi If any program executes faster under `valgrind` than without, something's very wrong with that programs code: `valgrind` basically executes the program with an emulated CPU that adds bounds-checks at every memory access, and these bounds-checks take time. It is expected for any process to be at least a factor 50 slower when executed under `valgrind`. The opposite means, that your program does something very different when running under `valgrind`, which means that it's exhibiting undefined behavior. If I were you, I'd definitely investigate this. – cmaster - reinstate monica Nov 12 '17 at 16:10
  • thanks, I check this and runtime is same in both of them. – Saeed Masoomi Nov 13 '17 at 13:39