3

Possible Duplicate:
C++ delete - It deletes my objects but I can still access the data?

I am curious about why I am getting the following behaviour with the following (rather contrived) code. I am using gcc 4.4.5 on Ubuntu 10.10

#include <iostream>

int main(int argc, char *argv[])
{
  int N = 5;
  int *myarr = new int[N];//create an integer array of size 5

  for (int i = 0; i < N; ++i)
    {
      myarr[i] = 45;
      std::cout << myarr[i] << std::endl;
    }  


  delete[] myarr;//kill the memory allocated by new
  std::cout << "Let's see if the array was deleted and if we get a segfault \n" ;

  for (int i = 0; i < N; ++i)
    {
      std::cout << myarr[i] << std::endl;
    }


  return 0;
}

The code compiles even with -Wall flag on. The output is

Desktop: ./a.out
45
45
45
45
45
Let's see if the array was deleted and if we get a segfault 
0
0
45
45
45
Desktop: 

How come the myarr array can still be accessed as if it were ever deleted without a segfault? Further even though the myarr array was deleted how come the values 45 still seem to be printed correctly in positions 2,3 and 4.

In short what is delete[] really doing here?

Community
  • 1
  • 1
curiousexplorer
  • 1,217
  • 1
  • 17
  • 24

7 Answers7

3

delete[] calls the destructor for each element in the array, and tells your computer that you will not use the memory any more. The memory is still there, you're just not allowed to use it.

What you are seeing is undefined behaviour. It might fail in all sorts of ways, but because your program is so short, it will probably work as you've seen most of the time.

Kleist
  • 7,785
  • 1
  • 26
  • 30
2

Freeing memory does not guarantee that you will get a segfault if you later try to access that memory. Basically, accessing memory after it has been freed results in undefined behaviour - anything can happen.

In your case, the delete[] operator is freeing the memory and returning it to your runtime library. However, the runtime library hangs on to the memory and doesn't immediately return it to the OS (after all, you might need it again fairly soon). The runtime library will manage its own data structures using memory that your application has already freed. For example, the zeros you see might be part of a free list structure.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
1

Operator delete[] only frees the memory. Accessing memory after a delete[] is undefined behaviour.

The memory pointed by myarr will probably still contain the values you had assigned for a while. That memory address will contain the same values until someone writes something to it.

mfontanini
  • 21,410
  • 4
  • 65
  • 73
1

The memory was deallocated, and some of it wiped as you can see. It can still be accessed, but the fact that your program is not crashing is mainly due to the fact that not enough time has passed for this memory to be allocated for different objects, or that you didn't try doing anything naughty with it, like using a value inside it as an offset for a buffer or something.

Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
0

What did you think the delete[] does? It's calling the destructor of all of the objects in the array and then freeing it. Your myarr pointer is now pointing to freed memory, and is an invalid pointer.

Evidently, the memory hasn't been reused yet so it still happens to contain the data that was present before you freed it, but this is undefined behaviour which means you cannot rely on it. If you do, you'll have all sorts of exciting hard-to-find bugs one day.

pndc
  • 3,710
  • 2
  • 23
  • 34
0

delete[] call the destructor and then tells the system that the previously allocated memory will not be of any further usage, but the pointer still points to the start address.

#include <iostream>

int main(int argc, char *argv[])
{
  int N = 5;
  int *myarr = new int[N];//create an integer array of size 5

  for (int i = 0; i < N; ++i)
    {
      myarr[i] = 45;
      std::cout << myarr[i] << std::endl;
    } 


  delete[] myarr;//kill the memory allocated by new
  std::cout << "Let's see if the array was deleted and if we get a segfault \n" ;

  int *dumb = new int[N];

  dumb[3]=0;

  for (int i = 0; i < N; ++i)
    {
      std::cout << myarr[i] << std::endl;
    }


  return 0;
}

and the output is:

45
45
45
45
45
Let's see if the array was deleted and if we get a segfault 
0
45
45
0
45

You don't get a segmentation fault because the memory is too small and probably has not been reserved by another process. But try this:

#include <iostream>

int main(int argc, char *argv[])
{
  int N = 50000;
  int *myarr = new int[N];//create an integer array of size 5

  for (int i = 0; i < N; ++i)
    {
      myarr[i] = 45;
      std::cout << myarr[i] << std::endl;
    }


  delete[] myarr;//kill the memory allocated by new
  std::cout << "Let's see if the array was deleted and if we get a segfault \n" ;
  std::cin >> N;
  int *dumb = new int[N];

  dumb[3]=0;

  for (int i = 0; i < N; ++i)
    {
      std::cout << myarr[i] << std::endl;
    }


  return 0;
}

and enter some number, e.g. 9000

0

All that has been already written here is true, I just want to shed some more light on why what you did is undefined behaviour.

  1. In terms of memory allocation for a process, operating system is not a retailer, you cannot get lets say 10 bytes, you can only request memory in pages (usually 1 page = 4KiB).
  2. But processes operate on smaller chunks, that is why each process has it own "allocator" - this is implementation of operator new and delete. These two beasts sit between your program and the OS. They request memory in pages (e.g. please give me 3 pages of memory) and manage these pages for your program (process).
  3. When you want to allocate let's say 10 bytes, the operator new will allocate (at least) one page (if needed) and give you a pointer pointing to memory on that page, it will also remember that from that address (that it gave you) 10 bytes are used.
  4. When you do not need those 10 bytes anymore, you call operator delete - this beast will make note that the 10 bytes (on the page mentioned above) are not used anymore. If the whole page is not used anymore it can (but not have to) be freed (given back to the system). When that happens if you try to access the freed memory - it will give you segmentation fault (the page is not owned by your process anymore), but if the page was not given back to the system, it is still available to you, (but you do not know that for sure)
  5. Even if the memory is still accessible you should not access it, because:
    • the contents may be reused for other allocations, which means that it can change
    • the contents can be (and often is) used by internal structures of new and delete. If you write to deleted memory you may cause corruption of these structures, that often results in segfaults in completely unexpected places (e.g. on delete[] in some other completely unrelated place in the code).

Please bear in mind, that all that I wrote above is only very simplified version, it is much complex then that, but I hope it will give you some idea how it all works "under the hood". Amen.

sirgeorge
  • 6,331
  • 1
  • 28
  • 33