删除动态分配的内存

时间:2013-12-10 08:22:38

标签: c++

我在动态内存分配方面面临一些概念性问题。首先,如果我写下以下代码

int *p = NULL;
delete p;

为什么我没有错误?我正在尝试删除指向任何东西的指针(在堆栈上)。如果我写下面的陈述

int *p = new int;
p = NULL;
delete p;

我再次没有编译或乱码错误。为什么? 如果我写下面的代码继续前进,我会收到运行时错误

int *p = new int;
p = NULL;
delete p;
delete p;

为什么呢?如果我写下面的代码,我没有错误

int *p = NULL;
delete p;
delete p;

为什么?任何人都可以从概念上解释这背后的原因吗?

6 个答案:

答案 0 :(得分:1)

我认为在你的第三个例子中你打算写

int *p = new int;
delete p;
delete p;

正式这会导致未定义的行为,这意味着任何事情都可能发生。实际上,您可能正在使用内存分配器来检查您要删除的指针是否指向其空闲内存池中。

其他人已经指出,删除空指针不会导致定义错误,因此无论你执行多少次都无关紧要。

答案 1 :(得分:0)

将空指针传递给delete运算符是一个无操作。标准是这样说的:

  

5.3.5 / 2

     

在[delete和delete []]中,如果delete的操作数值为空指针,则操作无效。


考虑一个拥有指向另一个对象的指针的对象。通常,当运行拥有对象的析构函数时,它会通过删除它来清理拥有对象的内存。但是在拥有对象也可能为null的情况下,我们将如何清理内存?一种选择是将每个删除包装在“if(X)delete x”类型的包装器中。但这是非常嘈杂的,因为没有真正的额外好处。因此,删除操作符会为您完成。

答案 2 :(得分:0)

“我正在尝试删除指向任何内容的指针(在堆栈上)。”

事实并非如此。您无法从堆栈中删除。使用delete删除堆上的内存块,其地址存储在指针中。指针本身就是一个堆栈变量。

答案 3 :(得分:0)

在每种情况下,你只是删除一个nullpointer,根据定义,它总是“安全的”,因为它是一个no-op(C ++标准明确地这样说)。

在第二个和第三个示例中,您将在删除之前将新值(nullpointer)重新分配给指针,这意味着您正在泄漏先前分配的整数。这通常不会发生(在这种情况下,你不会因为泄漏一个整数而死,但这不是一件好事。)

第三个和第四个示例中的双重删除通常是严重的编程错误,但它们在您的示例中是“无害的”,因为删除的指针是空指针(因此它是无操作)。


有点O / T:
请注意,我已将“安全”和“无害”放在上面的引号中是有充分理由的。我个人不同意Stroustrup先生的设计决定。
将nullpointer删除为“无害的无操作”实际上并不是一个好主意,即使意图可能是好的。 Stroustrup先生甚至更进一步允许delete设置指向nullponter的指针,并说他希望实现实际上是这样做的(幸运的是没有我知道的实现!)。

在我看来,分配的每个对象应该只删除一次,不能少,也不要经常删除。

一个表现良好,未破坏的程序可能(并且必须)删除指针的时间和频率是精确定义的,它不是随机未知的事情。删除必须恰好发生一次,并且程序必须完全了解它,因为必须确定对象是否有效(因为如果对象无效则使用该对象是非法的!)。

删除对象后设置指向空指针的指针会在以后取消引用已删除的对象时导致错误(这是一件好事),但防止双重删除。相反,它隐藏这个严重的编程错误,无声地忽略它。

如果程序删除指针两次,则程序逻辑被破坏,它无法正常工作。这不是可以忽略的东西,必须修复。因此,这样的程序应该崩溃。分配器通常会检测到双重删除,但通过重置指向空指针的指针,可以有效地禁用此检测机制。

如果选择在删除指针后重置指针,则应该(在我看来)将其设置为无效的非空指针值,例如(T*)1(T*)-1。这样可以保证两者解除引用和删除指针都会在第一时间崩溃。

没人喜欢看程序崩溃。但是,与不正确的程序逻辑持续不确定的时间,以及可能在随机场合崩溃或无声地破坏数据相比,第一次崩溃并且在第一次崩溃是好事

答案 4 :(得分:-1)

我认为如果你试图删除指针,实际上是删除了指针指向的对象内存中的位置。您可以使用参考:

来完成
int *p = NULL;

delete &p;

答案 5 :(得分:-1)

内部实现对我们的程序员来说是透明的。如您所见,delete NULL指针可能无害,但通常您应该避免这种情况。您可能已经看到过“请不要重新删除动态指针”等字样