简体   繁体   中英

Why I have to call delete on the “original” pointer?

I would like to know why in the following code the first delete won't free the memory:

#include <list>
#include <stdio.h>

struct abc {
    long a;

    abc() {
        puts("const");
    }
    ~abc() {
        puts("desc");
    }
};

int main() {

    std::list<abc*> test;

    abc* pA = new abc;
    printf("pA: 0x%lX\n", (unsigned long int)pA);
    test.push_back(pA);

    abc* pB = test.back();

    printf("pB: 0x%lX\n", (unsigned long int)pB);
    delete pB; // just ~abc()

    test.pop_back();

    delete pA; // ~abc() and free (works)

    puts("before double-free");

    delete pA; // ~abc() and second free (crash)

    return 0;
}

Output is:

const
pA: 0x93D8008
pB: 0x93D8008
desc
desc
before double-free
desc
*** glibc detected *** ./test: double free or corruption (fasttop): 0x093d8008 ***
...

I tried it with free() also but same behavior.

delete pA; // ~abc() and free (works)

puts("before double-free");

delete pA; // ~abc() and second free (crash)

These delete statements are not needed once you write delete pB . You've a misconception that delete pB only calls the destructor. No, it calls the destructor and also deallocates the memory.

Also, since you've already written delete pB , the next two further delete expressions invoke undefined behavior , which means anything can happen : the program may or may not crash!

Have a look at these topics:

Your first delete renders the pointer to invalid state. So use of that pointer now leads to undefined behaviour.

int* p = new int;
delete p;
delete p; //undefined behaviour

This is guaranteed to be fine by the standard (as pointed out in the first comment):

int* p = new int;
delete p;
p = 0;
delete p; //fine

First, you can't free memory allocated with new , you have to use delete .

Secondly, just because glibc doesn't detect the double free immediately, how do you know delete pB; isn't freeing it? That's what delete does, and from your own logging you're passing the same address to delete each time.

Thirdly: what are you actually trying to accomplish?

It's just an indiosyncracy of your compiler/platform that you had to call delete twice on pA before glibc complained ... for instance, on my current platform, which is OSX 10.6.8 with gcc version i686-apple-darwin10-gcc-4.2.1, I get the following output:

const
pA: 0x100100080
pB: 0x100100080
desc
desc
test(14410) malloc: *** error for object 0x100100080: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap

So you can see the first call to delete on pA , which by the standard results in undefined behavior since you didn't set the pointer to NULL or 0 , did get caught as an attempt to deallocate already deallocated memory by the C++ run-time on my platform.

Since the results of the double-delete are "undefined behavior", it's really up to the implementation and platform on what happens.

You may be able to detect allocation/deallocation memory errors quicker if you use the link against the glibc memory consistency checker by compiling with the -lmcheck flag.

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