'删除指针'只是意味着'*指针= 0'吗?

时间:2012-01-31 01:33:52

标签: c++ memory-management free destructor delete-operator

# include <iostream>

int main()  
{  
using std::cout;
int *p= new int;

*p = 10;
cout<<*p<<"\t"<<p<<"\n";
delete p;
cout<<*p<<"\t"<<p<<"\n";

return 0;

}

输出:
10 0x237c010
0 0x237c010

在删除p之后,为什么指针p保持其值?不删除释放指针p?
“释放指针”的确切含义是什么? 'delete p'是否只是意味着'* p = 0'?(从输出看来)

5 个答案:

答案 0 :(得分:6)

  

在删除p之后,为什么指针p保持其值?

这就是语言的设计方式。如果您希望将所持有的指针归零,则需要自己将其指定为零。指针p是另一块内存,与它指向的分配/对象分开。

  

不删除释放指针p?

它将析构函数称为对象并将内存返回给系统(如free)。如果它是一个数组(delete[]),将调用所有元素的析构函数,然后返回内存。

  

'释放指针'究竟是什么意思?

如果您需要系统中的一块内存,请分配它(例如使用new)。使用完毕后,使用相应的免费/删除调用将其返回。这是一种资源,你必须返回。如果你不这样做,你的程序就会泄漏(没有人想要这样做)。

答案 1 :(得分:2)

为了理解释放内存的含义,您必须首先了解分配内存的含义。以下是简化说明。

存在记忆。内存是一大堆你可以访问的东西。但由于它是全球性的,你需要一些方法来分配它。某种方式来管理谁可以访问哪些内存。管理内存分配的系统之一称为“堆”。

堆拥有一定数量的内存(一些由堆栈拥有,一些由静态数据拥有,但现在没办法)。在程序开始时,堆表示您无权访问堆拥有的内存。

new int的作用是双重的。首先,它进入堆系统并说:“我想要一块适合存储int的内存。”它返回一个指向这个的指针:一块堆,你可以安全地存储和检索一个int类型的值。

你现在是int一个new int的记忆的自豪拥有者。堆保证只要遵循其规则,无论你放置什么,都会保留,直到你明确地改变它。这是你和全能堆之间的契约。

int做的另一件事是用new int(5)值初始化那块堆。在这种情况下,它是默认初始化的,因为没有传递任何值(int将使用值5初始化它。)

从现在开始,您可以合法地在一段记忆中存储一个int。您可以检索存储在那里的delete p。并且你被允许做另外一件事:告诉堆你已经完成了使用那个内存。

当你致电p时,会发生两件事。首先,int被取消初始化。同样,因为它是delete,所以没有任何反应。如果这是一个类,它的析构函数将被调用。

但在那之后,int走到堆里说:“嘿堆:记住这个指向你给我的int的指针吗?我现在已经完成了它。”堆系统可以做任何想做的事情。也许它会清除内存,正如一些堆在调试版本中所做的那样。但是,在发布版本中,内存可能无法清除。

当然,堆可以做任何事情的原因是因为,时刻你删除了那个指针,你就与堆进入了一个新的协议。以前,你要求delete p的内存,并且堆必须使用。你拥有那个内存,并且只要你愿意,堆保证它是你的。放在那里的东西会留在那里。

在你获得乐趣后,你将它归还给堆。这是合同的来源。当你说p时,对于任何对象new int,你说的是:

我庄严地发誓不要再次触摸此内存地址了!

现在,如果再次调用new,堆可能会将该内存地址返回给您。它可能会给你一个不同的。但是,您只能在 deletedelete p; cout << *p << "\t" << p << "\n"; 之间的时间内访问堆分配的内存。

鉴于此,这是什么意思?

*p

用C ++的说法,这称为“未定义的行为”。 C ++规范有许多被称为“未定义”的东西。当您触发未定义的行为可能发生任何事情! *p可能为0. *p可能是以前的值。执行delete p 可能导致程序崩溃。

C ++规范是您和编译器/计算机之间的契约。它说你可以做什么,它说明系统如何响应。 “未定义的行为”是当你打破合同时,当你执行C ++规范所说的你不应该做的事情时会发生的事情。那时,任何事情都可能发生。

当您致电p时,您使用delete p告诉系统您已完成。再次使用它,你躺在系统。因此,系统不再需要遵守任何规则,例如存储要存储的值。或者继续跑步。或者不是从你的鼻子中产生恶魔。或者其他什么。

你破坏了规则。你必须承受后果。

所以不,*p = 0不等同于p。后者只是意味着“将0设置为p指向的内存”。前者的意思是“我已经完成了使用{{1}}所指向的记忆,,我不再使用它,直到你告诉我可以。”

答案 2 :(得分:1)

  

在删除p之后,为什么指针p保持其值?不删除会释放指针p?

释放指针指向的内存(在调用任何适当的析构函数之后)。指针本身的值不变。

  

'释放指针'究竟是什么意思?

如上所述 - 它意味着释放指针所指向的内存。

  

'删除p'是否只是意味着'* p = 0'?(从输出中看来)

没有。系统不会 向已释放的内存写入任何内容,如果它确实写了一些内容,则不必编写0。但是,系统通常必须以某种方式管理该内存,并且实际上可能会写入指针所指向的内存区域。此外,刚刚释放的内存可以分配给其他东西(在多线程应用程序中,可能会在delete操作甚至返回之前发生)。该内存块的新所有者当然可以将任何他们想要的内容写入该内存。

指向释放的内存块的指针通常称为“悬空”指针。取消引用悬空指针(用于读取或写入)是错误的。您有时会看到代码在删除指针后立即立即为指针分配NULL0,有时使用宏或函数模板删除和清除指针。请注意,这不会修复所有带悬空指针的错误,因为其他指针可能已设置为指向内存块。

处理这类问题的现代方法是避免使用原始指针,而是使用shared_ptrunique_ptr等智能指针。

答案 3 :(得分:0)

delete p只是释放在调用new运算符期间分配的内存。它不会更改指针的值或释放的内存的内容。

答案 4 :(得分:0)

(注意以下不是它实际上是如何工作的,所以要带上一粒盐。)

在new的实现中,当你说“int * p = new int;”时,它会保留所有可用内存的列表。它从可用内存列表中删除了一个int大小的块并将其提供给您。当你运行“删除p;”它被放回可用内存列表中。如果您的程序在没有调用删除的情况下调用了30次,那么您将获得30个不同的int大小的块。如果你调用new然后连续删除30次,你可能(但不一定)获得相同的int大小的块。这是因为你说当你调用delete时你不再使用它了,所以new可以自由地重用它。

TLDR;删除通知新的此内存部分再次可用,它不会触及您的变量。