What happens in a double delete?

2019-01-03 16:53发布

Obj *op = new Obj;
Obj *op2 = op;
delete op;
delete op2; // What happens here?

What's the worst that can happen when you accidentally double delete? Does it matter? Is the compiler going to throw an error?

7条回答
劳资没心,怎么记你
2楼-- · 2019-01-03 17:27

It causes undefined behaviour. Anything can happen. In practice, a runtime crash is probably what I'd expect.

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-01-03 17:29

It's undefined behavior, so the actual result will vary depending on the compiler & runtime environment.

In most cases, the compiler won't notice. In many, if not most, cases, the runtime memory management library will crash.

Under the hood, any memory manager has to maintain some metadata about each block of data it allocates, in a way that allows it to look up the metadata from the pointer that malloc/new returned. Typically this takes the form of a structure at fixed offset before the allocated block. This structure can contain a "magic number" -- a constant that is unlikely to occur by pure chance. If the memory manager sees the magic number in the expected place, it knows that the pointer provided to free/delete is most likely valid. If it doesn't see the magic number, or if it sees a different number that means "this pointer was recently freed", it can either silently ignore the free request, or it can print a helpful message and abort. Either is legal under the spec, and there are pro/con arguments to either approach.

If the memory manager doesn't keep a magic number in the metadata block, or doesn't otherwise check the sanity of the metadata, then anything can happen. Depending on how the memory manager is implemented, the result is most likely a crash without a helpful message, either immediately in the memory manager logic, somewhat later the next time the memory manager tries to allocate or free memory, or much later and far away when two different parts of the program each think they have ownership of the same chunk of memory.

Let's try it. Turn your code into a complete program in so.cpp:

class Obj
{
public:
    int x;
};

int main( int argc, char* argv[] )
{
    Obj *op = new Obj;
    Obj *op2 = op;
    delete op;
    delete op2;

    return 0;
}

Compile it (I'm using gcc 4.2.1 on OSX 10.6.8, but YMMV):

russell@Silverback ~: g++ so.cpp

Run it:

russell@Silverback ~: ./a.out
a.out(1965) malloc: *** error for object 0x100100080: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap

Lookie there, the gcc runtime actually detects that it was a double delete and is fairly helpful before it crashes.

查看更多
啃猪蹄的小仙女
4楼-- · 2019-01-03 17:36

While this is undefined:

int* a = new int;
delete a;
delete a; // same as your code

this is well defined:

int* a = new int;
delete a;
a = nullptr; // or just NULL or 0 if your compiler doesn't support c++11
delete a; // nothing happens!

Thought I should post it since no one else was mentioning it.

查看更多
forever°为你锁心
5楼-- · 2019-01-03 17:38

No, it isn't safe to delete the same pointer twice. It is undefined behaviour according to C++ standard.

From the C++ FAQ: visit this link

Is it safe to delete the same pointer twice?
No! (Assuming you didn’t get that pointer back from new in between.)

For example, the following is a disaster:

class Foo { /*...*/ };
void yourCode()
{
  Foo* p = new Foo();
  delete p;
  delete p;  // DISASTER!
  // ...
}

That second delete p line might do some really bad things to you. It might, depending on the phase of the moon, corrupt your heap, crash your program, make arbitrary and bizarre changes to objects that are already out there on the heap, etc. Unfortunately these symptoms can appear and disappear randomly. According to Murphy’s law, you’ll be hit the hardest at the worst possible moment (when the customer is looking, when a high-value transaction is trying to post, etc.). Note: some runtime systems will protect you from certain very simple cases of double delete. Depending on the details, you might be okay if you happen to be running on one of those systems and if no one ever deploys your code on another system that handles things differently and if you are deleting something that doesn’t have a destructor and if you don’t do anything significant between the two deletes and if no one ever changes your code to do something significant between the two deletes and if your thread scheduler (over which you likely have no control!) doesn’t happen to swap threads between the two deletes and if, and if, and if. So back to Murphy: since it can go wrong, it will, and it will go wrong at the worst possible moment. A non-crash doesn’t prove the absence of a bug; it merely fails to prove the presence of a bug. Trust me: double-delete is bad, bad, bad. Just say no.

查看更多
smile是对你的礼貌
6楼-- · 2019-01-03 17:43

Undefined behavior. There are no guarantees whatsoever made by the standard. Probably your operating system makes some guarantees, like "you won't corrupt another process", but that doesn't help your program very much.

Your program could crash. Your data could be corrupted. The direct deposit of your next paycheck could instead take 5 million dollars out of your account.

查看更多
欢心
7楼-- · 2019-01-03 17:51

The compiler may give a warning or something, especially in obvious (like in your example) but it is not possible for it to always detect. (You can use something like valgrind, which at runtime can detect it though). As for the behaviour, it can be anything. Some safe library might check, and handle it fine -- but other runtimes (for speed) will make the assumption you call is correct (which it's not) and then crash or worse. The runtime is allowed to make the assumption you're not double deleting (even if double deleting would do something bad, e.g. crashing up your computer)

查看更多
登录 后发表回答