开发者

Why doesn't delete destroy anything?

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 p开发者_开发技巧oint 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;  
}  

Any clue ?


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()
    {
        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.


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

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

delete pTest;
pTest = 0;


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.


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.


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.


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.)


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


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.


Calling delete for a pointer marks the memory block pointed by it to 'free memory'. It doesn't destroy the items in the memory right away. The 'items' get destroyed only after the process has returned given that 'delete' was used for the pointer pointing to that memory block. In case 'delete' isn't used, it stays there forever resulting in a memory leak.

To solve your problem, just:

delete pTest;
pTest=NULL;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜