在C++中,当您多次释放指针时会发生什么?

28
int main() {
    Employee *e = new Employee();

    delete e;
    delete e;
    ...
    delete e;
    return 0;
}

5
黄瓜错误,重启宇宙。 - Brian Postow
9
为什么要踩?这是一个简单而直接的问题。仅因为你认为它是一个初级问题,并不意味着它应该被踩。 - John Dibling
8个回答

45
你如果尝试通过指针多次delete一个对象,就会出现未定义行为
这意味着几乎任何事情都可能发生,从“表面工作”到“崩溃”或完全随机的结果。

我已经尝试过了,它没有崩溃。但是我认为你可能会释放其他部分程序正在使用的内存。 - flopex
2
它可能不会在那一刻崩溃。但如果它破坏了堆的某个部分,那么有很大的机会在之后的任意时间发生崩溃。然而,它可能会成为一种潜伏的定时炸弹。直到稍后发生某些看似无关的操作接触到已损坏的部分,然后 - TheUndeadFish

19

这是未定义的行为,因此可能发生任何事情。

可能发生的情况很糟糕。通常,自由存储区是一个仔细管理的已分配和未分配块的系统,newdelete会进行记录以保持所有内容的一致状态。如果再次使用delete,系统可能会在无效数据上执行相同的记录,使得自由存储区处于不一致的状态。这被称为“堆栈破坏”。

一旦发生这种情况,您对newdelete的任何操作都可能产生不可预测的结果,包括尝试写入应用程序内存区域之外、静默损坏数据、错误地认为没有更多的内存,或者双重或重叠的分配。如果你很幸运,程序很快就会崩溃,但你仍然难以解决问题。如果你不走运,它将继续运行并产生错误的结果。


13

除了"未定义行为"这个老话可以意味着从什么都不会发生到地狱第七层的大门在主内存中打开,实际上在大多数实现中通常会发生的是程序将继续运行直到删除,然后在稍后某个无关的内存分配中神秘地崩溃。


是的,这是可能发生的更好的事情之一。 - David Thornley
4
经常当我遇到神秘的内存崩溃时,我希望地想,如果在主内存中打开了通往地狱第七层的大门就好了…… - Brian Postow

4

你很可能涉及到“未定义行为”的领域。

在许多系统中,这会导致崩溃;例如,在我的Linux机器上:

*** glibc detected *** ./cctest: double free or corruption (fasttop): 0x0000000000d59900 ***
======= Backtrace: =========
/lib/libc.so.6[0x7f399f4cbdd6]
/lib/libc.so.6(cfree+0x6c)[0x7f399f4d074c]
./cctest[0x400a7a]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7f399f474abd]
./cctest[0x400959]

3
如果你非常幸运,它会崩溃。通常情况下,它会积累业力,直到你的CEO向最重要的新客户演示代码时,它会破坏/摧毁他们的所有数据。
在检查或调试版本中,通常会捕获此类问题,但它可能完全未被检测到,并在以后造成大混乱。当涉及多个线程时,这尤其深刻。

3
如果您担心这种情况可能发生在您的应用程序中,要么完全停止使用原始指针,以便您不需要删除(例如切换到shared_ptr),要么在删除后始终将指针设置为NULL(或0,或更好的是nullptr)。 在空指针上调用delete保证什么也不会发生。

4
我一直不喜欢后一种解决方案。删除指针两次是错误的,而将指针设置为null只会隐藏问题。 - GManNickG

2

0

尽管有时我们可以在删除指针后访问内存位置,但我们不应再次删除同一指针或将值分配给该指针(会导致不一致的行为)。

但是,我们可以使用相同的指针变量来指向不同的内存地址(有效内存)。

int *p = new int(10);
std::cout << "in main" << std::endl;
std::cout <<*p << std::endl;
std::cout << p << std::endl;
std::cout << &p<< std::endl;
delete p;
std::cout << "in main2 after delete" << std::endl;
std::cout <<*p << std::endl;
std::cout << p << std::endl;
std::cout << &p<< std::endl;

p = new int(100);
std::cout << "in main3" << std::endl;
std::cout <<*p << std::endl;
std::cout << p << std::endl;
std::cout << &p<< std::endl;

导致输出

in main
10
0x558b597a8eb0
0x7fff8f7a5ba0
in main2 after delete
0
0x558b597a8eb0
0x7fff8f7a5ba0
in main3
100
0x558b597a8eb0
0x7fff8f7a5ba0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接