如果我为对象动态分配内存位置,int
如下所示:
int *x = new int;
完成后,想要释放堆上的内存,我将执行以下操作:
delete x;
现在,如果我没有执行以下操作:
x = NULL;
会x
指向另一个地址吗?更新: another
而不是many
说我没有做x = NULL
,又做了一个 delete x;
,会发生什么?
如果我为对象动态分配内存位置,int
如下所示:
int *x = new int;
完成后,想要释放堆上的内存,我将执行以下操作:
delete x;
现在,如果我没有执行以下操作:
x = NULL;
会x
指向另一个地址吗?更新: another
而不是many
说我没有做x = NULL
,又做了一个 delete x;
,会发生什么?
x
(除了= NULL
- 即 imo,不好的做法)都是未定义的。注意:一些运行时系统会保护您免受某些非常简单的双重删除情况的影响。根据详细信息,如果您碰巧在其中一个系统上运行,并且如果没有人将您的代码部署在另一个处理方式不同的系统上,并且如果您要删除没有析构函数的东西,并且如果您在两次删除之间没有做任何重要的事情,并且如果没有人更改您的代码以在两次删除之间做一些重要的事情,并且您的线程调度程序(您可能无法控制!)不会碰巧在之间交换线程这两个删除了and if,and if,and if。所以回到墨菲:既然它可能出错,它就会出错,而且它会在最糟糕的时刻出错。
在 之后delete
,指针通常仍将包含(现在空闲的)内存的地址。第二个delete
给出未定义的行为,所以不要这样做。
它将调用未定义的行为。如果你不这样做,x=NULL
那么x
将指向一个无效的内存位置,如果你尝试使用它将导致未定义的行为。
类型:
int main(){
int* i = new int;
std::cout << i << std::endl;
delete i;
std::cout << i << std::endl;
delete i;
}
结果:
0x8e19008
0x8e19008
** 检测到 glibc ** ./a.out:双重释放或损坏(fasttop):0x08e19008 *
如您所见,地址保持不变,但第二次删除以运行时错误结束。行为可能在细节上取决于环境,但作为一般规则,它不会起作用。
在已删除的内存上调用 delete 将导致未定义的行为。通常,您的程序会崩溃。
删除 x 后,它将指向的位置是“编译器相关”。在调用 delete 之前,大多数编译器只会让它指向它所在的位置。但是那个内存地址不再有效,因此不应该被调用。
出于同样的原因,如果需要的话,必须非常明智和谨慎地使用“删除这个”。:-)
第二次删除未定义。
作为旁注,有一些工具可以检测双重删除。周围最好的之一是Valgrind。