# 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'?(从输出看来)
答案 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
,堆可能会将该内存地址返回给您。它可能会给你一个不同的。但是,您只能在 delete
和delete 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
操作甚至返回之前发生)。该内存块的新所有者当然可以将任何他们想要的内容写入该内存。
指向释放的内存块的指针通常称为“悬空”指针。取消引用悬空指针(用于读取或写入)是错误的。您有时会看到代码在删除指针后立即立即为指针分配NULL
或0
,有时使用宏或函数模板删除和清除指针。请注意,这不会修复所有带悬空指针的错误,因为其他指针可能已设置为指向内存块。
处理这类问题的现代方法是避免使用原始指针,而是使用shared_ptr
或unique_ptr
等智能指针。
答案 3 :(得分:0)
delete p
只是释放在调用new
运算符期间分配的内存。它不会更改指针的值或释放的内存的内容。
答案 4 :(得分:0)
(注意以下不是它实际上是如何工作的,所以要带上一粒盐。)
在new的实现中,当你说“int * p = new int;”时,它会保留所有可用内存的列表。它从可用内存列表中删除了一个int大小的块并将其提供给您。当你运行“删除p;”它被放回可用内存列表中。如果您的程序在没有调用删除的情况下调用了30次,那么您将获得30个不同的int大小的块。如果你调用new然后连续删除30次,你可能(但不一定)获得相同的int大小的块。这是因为你说当你调用delete时你不再使用它了,所以new可以自由地重用它。
TLDR;删除通知新的此内存部分再次可用,它不会触及您的变量。