简体   繁体   中英

Why doesn't deleting my pointer delete my pointer?

So to understand new/delete better (really to prove to myself with small examples why virtual destructors are needed for interfaces), I want to understand memory leaks, so that I may live in fear of them. But I am having a hard time getting my leak on, so to speak; actually, I am have a hard time with new/delete too.

Here's my simplest version:

int* P1 = new int(43);

cout<<"P1 = "<<P1<<endl;
cout<<"*P1 = "<<*P1<<endl;

delete P1;

cout<<"P1 = "<<P1<<endl;
cout<<"*P1 = "<<*P1<<endl;

This prints:

P1 = 0xcc0340
*P1 = 43
P1 = 0xcc0340
*P1 = 43

I had something more complicated inside of a class, but this example illustrates my fail. I thought delete takes a pointer and frees it's memory, thereby invalidating the pointer or at least what it points to? I must be doing something very simple very wrong.

You are causing undefined behaviour . This means that anything can happen. Since something did indeed happen, everything behaves as documented. (Sometimes "something" looks very similar to something else that you might erroneously expect. Doing exactly what you think you were trying to achieve is one of the possible allowed instances of "undefined behaviour".)

Note also that a "memory leak" is sort of the opposite of what you're trying to do - in a memory leak you forget to free memory, whereas you already freed the memory and are now accessing invalid memory.

Here's a real memory leak, which also does not cause undefined behaviour -- don't confuse "bad but correct" with "incorrect" programming!

int * factorial(int * n)
{
  if (*n == 0) return new int(1);
  else return new int(*n * *factorial(*n - 1));
}

I must be doing something very simple very wrong.

You're absolutely right. Your code is doing something very simple very wrong, and you've paid the ultimate price - not seeing any negative results . Sometimes, you do things wrong, and nothing bad happens. This is the worst possible outcome, because you may not realize your code is wrong, and you'll continue to use it, until one day your code breaks unexpectedly, and you'll have no idea where or how because it's always worked before. It'll break somewhere completely irrelevant to the actual part that's wrong, and you'll spend hours trying to track it down and figure out why it's broken.

When you do things wrong, it's undefined behavior. That means anything can happen. At best, your code crashes and segfaults and blinking lights come on saying "YOU'RE USING FREED MEMORY" and everything is very clear. At worst, demons fly out of your nose . But just above that, the second worst possible outcome is that everything appears to work as you intended it to.

This would be a memory leak:

int* P1 = new int(43);
     P1 = new int(42);

Allocating memory without deleting it again.

// Reserve some memory for an int and set that memory to the value 43.
int* P1 = new int(43);

// Print the address of the reserved memory.
cout<<"P1 = "<<P1<<endl;
// Print the contents of that memory.
cout<<"*P1 = "<<*P1<<endl;

// Free the memory - it is no longer reserved to you.
delete P1;

// int* P2 = new int(47);    

// Print the address of the memory. It still holds the address to 
// the memory that used to be reserved for you.
cout<<"P1 = "<<P1<<endl;

// Print the current value of the memory that used to be reserved.
cout<<"*P1 = "<<*P1<<endl;

If you would uncomment the P2 line, it is quite likely that it would be assigned the same memory which would change the value printed at the last line.

Accessing memory that has been freed with delete causes undefined behaviour as others have pointed out. Undefined includes crashing in strange ways on some cases (only during full moon perhaps? ;-). It also includes everything working perfectly well for now, but with the bug being a mine that can trip off whenever you make another change anywhere else in your program.

A memory leek is when you allocate memory with new and never free it with delete . This will usually not be noticed until someone runs your program for a longer period and finds out that it eats all the memory of the system.

This code

delete P1;

cout<<"P1 = "<<P1<<endl;
cout<<"*P1 = "<<*P1<<endl;

causes undefined-behavior. So anything can happen. It's much easier to cause a memory leak:

for(;;) new int;

Dereferencing a deleted pointer is undefined behavior, as already explained, ie you are doing something wrong. Compilers may help you find that error by changing the pointer's value to some magic value that will always cause dereferencing the pointer to fail and can give you a clue that it's because it was previously deleted.

A quick test showed the following behavior for me:
MSVC2010:
debug build: *P1 = 0xfeeefeee
release build: *P1 = <random>
GCC 4.6:
debug & release builds: *P1 = 0

So you were just (un)lucky that you got again the original value. I recommend you to always build in debug mode for testing your programs (even if you aren't debugging) because it adds additional sanity checks to your code.

The memory is freed but it is not cleaned. The value may stay in memory until some other process writes a new value in that location.

Delete doesn't invalidate the pointer. It releases the memory it points to back to the heap. In this case, the memory hasn't been reused and therefore still contains the same content. At some point that memory WILL be reused and then you get the undefined behavior that others speak of.

This isn't a memory leak though. That's when you point the pointer to another memory allocation (or just discard the pointer) without freeing the memory it points to. The first then stays allocated and, as you've no references to it, you've no way of freeing it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM