views:

321

answers:

8

I'm playing a little with memory dynamic allocation, but I don't get a point. When allocating some memory with the new statement, I'm supposed to be able to destroy the memory the pointer points to using delete.

But when I try, this delete command doesn't seem to work since the space the pointer is pointing at doesn't seem to have been emptied.

Let's take this truly basic piece of code as an example:

#include <iostream>  

using namespace std;

int main()  
{  
    //I create a pointer-to-integer pTest, make it point to some new space,  
    // and fulfill this free space with a number;  
    int* pTest;  
    pTest = new int;  
    *(pTest) = 3;  
    cout << *(pTest) << endl; 

    // things are working well so far. Let's destroy this
    // dynamically allocated space!
    delete pTest;

    //OK, now I guess the data pTest pointed to has been destroyed 
    cout << *(pTest) << endl; // Oh... Well, I was mistaking.  

    return 0;  
}  

I guess this a very very noob question. Any clue ?

+4  A: 

delete operator calls the destructor of the object and deallocates the memory previously allocated to the object. It doesn't affect the pointer variable that points to the deleted object.

So when dereferencing a pointer pointing to a destroyed object, you'll get trouble.

Cătălin Pitiș
+7  A: 

Calling delete will mark the memory area as free. It won't necessary reset it's old value.

You are advised to set your pointer to 0, after calling delete:

delete pTest;
pTest = 0;
Macmade
I would instead advise to not use the variable _at all_ after calling `delete` (...unless, of course, it is re-assigned to something else).
stakx
A better solution is to make sure you variable goes out of scope soon after deletion and thus can not be re-used.
Martin York
+26  A: 

It's time to learn what undefined behavior is. :)

In C++, when you do something illegal/nonsensical/bad/etc. the standard often says that "it leads to undefined behavior." This means that from that point forward, the state of your program is completely non-guaranteed, and anything could happen.

At the point where you do your last *(pTest), you get undefined behavior. This is because pTest does not point to a valid object, and dereferencing such a pointer is undefined. So what you're seeing is totally allowed: undefined output.

All you've done is said "I'm finished with this allocation." Once you've said that, you shouldn't (and indeed, cannot) inspect or care about that memory any longer. It doesn't even make conceptual sense to deallocate something then try to use it; you've said you were done!

Your output is somewhat predictable though: likely, your OS simply says "okay, thanks for the memory" and that's it. It has no reason to actually "reset" the memory, or do anything special. That would indeed be a waste of time, when nobody (including your own program) is not using it.

But remember, this output is completely undefined. Don't try to use objects that don't exist. Perhaps a better test would have been:

#include <iostream>

struct foo
{
    ~foo(void)
    {
        std::cout << "foo is gone :(" << std::endl;
    }
};

int main(void)
{
    foo* f = new foo();
    delete f; // you'll see that the object is destroyed.
}

Although it seems you were looking to see what happens with the memory itself. Just remember that it makes no sense to get rid of memory then try to use it, so the answer is: who knows. It's up to your specific platform, which C++ doesn't care about.

GMan
The ugly thing about undefined behavior is that it most of the time looks good.
peterchen
@Matteo: Thanks, I'm on a typo-fest today.
GMan
No problem :) (random text to reach 15 characters)
Matteo Italia
+1 for the first sentence (and the answer too :-) )
Kedar
Excellent ! Thank you a lot, what's going on makes perfectly sense to me, now.
Kamixave
A: 

It could have referred to any piece of mapped memory. Or maybe unmapped memory, depending upon how long your program has been executing, details of memory allocations, and if the libraries are returning memory to the OS later on...

If delete actually cleared all the memory that is being deleted, programs would spend a significantly longer time running, because they'd waste a lot of time scrubbing memory that will probably be overwritten sooner or later anyway. It might be good for debugging, but in production use, there's just not much call for actually scrubbing memory contents. (Crypto keys are a good exception, of course; scrubbing those before calling delete or free is a good idea.)

sarnold
+1  A: 

What would destroying the data mean? I suppose it could zero it out, but why bother? It's assumed dirty when we get it from the environment, so why clean it before we return it? We don't care what's in it, because we are relinquishing our right to read it. And as to why delete doesn't zero out the pointer itself:

http://www2.research.att.com/~bs/bs_faq2.html#delete-zero

jjujuma
+2  A: 

Dereferencing a pointer that points to deallocated memory is undefined behavior.

Many times it will just work, because the memory provided by new is usually part of a bigger chunk of allocated memory that the allocator manages. When you call delete, it will call the relevant destructors and mark the memory as free, which usually means "ready for reuse". So, looking in that memory you'll find the same data that was there before the call to delete, or some other data if that chunk of memory has been reassigned after a new call.

Note that nothing forbids that the new/delete allocator works as a thin wrapper around the OS virtual memory functions, so when all the allocated blocks relative to a page has been deallocated, the whole page is freed and any attempt to access it results in an address violation.

TL,DR version: don't deference pointers which point to deallocated memory: it may work sometimes, sometimes will give you back garbage, sometimes it will trigger an access violation.

A good way to notice immediately if you're doing this kind of mistake is to set your pointers to NULL after deleting the memory they point to: if your code tries to dereference a NULL pointer, on almost any system this will make the application crash, so faults like these won't go unnoticed.

Matteo Italia
A: 

Just a simple example to illustrate what might happen, and what the undefined behaviour that some people mentioned means.

If we add two extra lines of code before the print:

delete pTest;

int *foo = new int;
*foo = 42;

cout << *pTest << endl;

The printed value of pTest could very well be 3, as it was in your case. However, the printed value could also be 42. As the pTest pointer was deleted, its memory was freed. Because of this, it is possible that the foo pointer will point to the same location in memory that pTest used to point to before it was deleted.

Alderath
+2  A: 

The answer is performance.

It's a great debug aid to fill all freed memory with an invalid value (0xCCCCCCCC, 0xDEADDEAD, etc.) to catch attempts to use stale pointers to already-freed memory.

But modifying a freed memory costs CPU time, so for performance reasons, the OS will just add the freed memory block to its "free" list, and leave the contents intact.

MaxVT