3

My code:

#include<iostream>
#include<cstdlib>

using namespace std;

int main()
{
    int * p;
    p = new int[5];
    p[0] = 34;
    p[1] = 35;
    p[2] = 36;
    p[3] = 44;
    p[4] = 32;
    cout << "Before deletion: " << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << p[i] << endl;
    }

    delete[] p;
    cout << "After deletion: " << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << p[i] << endl;
    }
}

If delete[] is supposed to delete all the memory blocks created by the new then why does only the first two elements get deleted here?

This is the output:

Before deletion: 
34
35
36
44
32
After deletion: 
0
0
36
44
32

One possible reason I could think of is that it removes the first two which some how makes the memory management think that the whole block is free to be reallocated again when needed. Though this is a complete guess on my part and I don't know the real reason.

aste123
  • 1,223
  • 4
  • 20
  • 40
  • 2
    Accessing `p[i]` after `p` is deleted is undefined behaviour. – Brian Bi Apr 25 '14 at 20:24
  • How do you think only the first two elements are deleted? – László Papp Apr 25 '14 at 20:24
  • 1
    How do you know that only the first two elements are deleted? What would deleting an int even mean? Try this again with an object, instead of a primitive `int`, and have the object send a message to `cout` when its destructor is called. – adpalumbo Apr 25 '14 at 20:25
  • @adpalumbo Thank you! That seems like a proper way of checking whether memory has actually been freed. – aste123 Apr 25 '14 at 20:31
  • @aste123: no, that is not any more proper since memory de-allocation happens in both cases, but with a custom type, the destructor is also invokved. Also, do not confuse delete with free. – László Papp Apr 25 '14 at 20:36
  • possible duplicate of [Can a local variable's memory be accessed outside its scope?](http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) –  Apr 25 '14 at 21:32
  • @delnan: I might be completely wrong here but here is my take on this: In my question, the memory has been allocated using `new` which means it is not released when it goes out of scope. To release the memory we have to use `delete[]`. Now there are two reasons why we can access the value in the memory location: 1. `delete[] didn't do its work`, 2. accessing out of scope memory location can give any result - `UB`. I was able to access the previous stored values so I wasn't sure if it was case 1 or not. My question is solely asking if `delete` is doing its work properly. Apologies if I'm wrong. – aste123 Apr 25 '14 at 21:41
  • The reason you can access the memory, and the reason you see confusing behaviour, is the exact same as explained in the question. You just have to think "deallocated" instead of "out of scope". –  Apr 25 '14 at 21:43
  • @delnan ok, thanks. Sorry for the trouble. – aste123 Apr 25 '14 at 21:44
  • @LaszloPapp Sorry got a bit busy. Done now. – aste123 Apr 28 '14 at 22:07

5 Answers5

3

There's no need to clear (as in change the value) of a deleted element, it only means that the allocator is free to use the space it occupied for whatever it wants, and that accessing the values results in undefined behaviour.

You have experienced a really nasty result of this, which is that some values remain unchanged, while successive runs of the same program might (and you should assume that will) have different results.

lccarrasco
  • 2,031
  • 1
  • 17
  • 20
2

It is not the first two items deleted, but all of them. That memory area could now be reused by further new operation, but there is no guarantee what is left in that memory area.

It is completely possible that you would see different results for different machines, subsequent runs on the same machine, different compiler versions and so on. Just do not rely on it.

However, you are accessing a dangling pointer afterwards which is Undefined Behavior (shortly UB).

Just in case, if you call delete without the square brackets, all the memory is de-allocated, but destructors may not be called. That is also UB even though you do not have custom types in this case, just ints.

In your case, it is exactly the same UB behavior with delete as well as delete[], respectively. That is why you see the same results in both cases for your current runs, but then again, even that is not guaranteed.

Ideally, you would need to set them to zero, too, but really, you should consider using a smart pointer, like unique_ptr.

László Papp
  • 51,870
  • 39
  • 111
  • 135
  • If I use delete instead of delete[], I get the same behaviour. Shouldn't the memory location next to the one that is being released still have the same value as `35`. I understand that I shouldn't use delete for an array allocated by new but I wanted to see the behaviour and it is confusing. – aste123 Apr 25 '14 at 20:43
  • @aste123: updated the answer with further information about it. – László Papp Apr 25 '14 at 20:54
1

Q: If delete[] is supposed to delete all the memory blocks created by the new then why does only the first two elements get deleted here?

A: The conclusion is incorrect. Try the following:

#include <iostream>

struct A
{
   A() : a(0) {}
   ~A() { std::cout << "Came to ~A(). a = " << a << std::endl;}
   int a;
};

int main()
{
   A* ap = new A[5];
   for (int i = 0; i < 5; ++i )
   {
      ap[i].a = i;
   }

   delete [] ap;
}

I get the following output:

Came to ~A(). a = 4
Came to ~A(). a = 3
Came to ~A(). a = 2
Came to ~A(). a = 1
Came to ~A(). a = 0
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

A pointer is not magic. It is effectively an unsigned integer of machine word size which refers to a memory address. Changing the value of a memory location from whatever it is to 0 is not deleting anything. When you call delete or delete [] all you've done is told the memory allocator that you are done with that memory and it is free to do (or not do) whatever it wants with that memory. After you call delete, what might be in that memory is undefined, you have no right to expect it to contain anything in particular, and you have no right to access it. Accessing memory that has been freed is like entering an apartment that you moved out of that you still have a key to; you might get away with it or you might get an access violation.

For types with destructors, the memory allocator will call the destructor for each object in the block of memory before reclaiming the memory block. ints have no destructor, so there's nothing extra for it to do.

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • Thank you. Is a very short explanation possible of how compiler (or OS or even the cpu, whichever part controls it) knows which memory location has already been taken and which one is free for reallocation? – aste123 Apr 25 '14 at 21:21
  • 1
    It's a complicated subject. But you can know that what `new` gives you is safe until you give it back via `delete`. To learn all about it is a matter for a book or class on memory management, compilers, and operating systems. Look to the Dinosaur Book (http://codex.cs.yale.edu/avi/os-book/OS8/os8j/slide-dir/index.html) or the Dragon Book (http://dragonbook.stanford.edu/). – Rob K Apr 26 '14 at 05:33
0

delete[] p releases the memory held by p, but doesn't (necessarily) overwrite it. The old data will remain there indefinitely.

dlf
  • 9,045
  • 4
  • 32
  • 58