为了理解释放内存的含义,首先必须了解分配内存的含义。以下是一个简化的解释。
存在着内存。内存是一大块可以访问的东西。但是因为它是全局的,所以需要一些方法来划分它。需要一些方法来管理谁可以访问哪些内存片段。一个管理内存分配的系统称为“堆”。
堆占有一些内存(一些由栈和静态数据拥有,但现在不要管这些)。在程序开始时,堆会说你没有访问任何堆内存的权限。
new int
做的两件事情。首先,它向堆系统请求:“我想要一个适合存储
int
类型值的内存块。”它得到了指向这个内存块的指针:一个堆内存块,你可以在其中安全地存储和检索一个
int
类型的值。
您现在拥有一个
int
大小的内存。堆保证只要遵循其规则,您放置在那里的任何内容都将被保存,直到您明确更改为止。这是您与万能堆之间的契约。
new int
的另一件事是用一个
int
值初始化该堆内存块。在这种情况下,它是默认初始化的,因为没有传递值(
new int(5)
将使用值5进行初始化)。
从此时起,您可以在这个内存块中合法地存储一个
int
。您可以检索存储在那里的
int
。您还可以做一件事:告诉堆您已经完成使用该内存。
当您调用
delete p
时,会发生两件事。首先,
p
被去初始化。再次强调,因为它是一个
int
,所以什么也不会发生。如果这是一个类,则将调用其析构函数。
但在此之后,
delete
会向堆发送消息:“嘿,堆:你给我的指向
int
的指针还记得吗?我现在用完了。”堆系统可以做任何它想做的事情。一些堆在调试版本中会清除内存。但在发布版本中,内存可能不会被清除。
当然,堆可以随心所欲地做任何事情的原因是,一旦您删除该指针,就会与堆进入新的协议。以前,您请求一个适合存储
int
类型值的内存块,堆满足了您的要求。您拥有了该内存,堆保证它是您的,只要您想要它。您放置在那里的内容将保留在那里。
在你玩耍后,你将其放回了堆中。这就是合同的作用。当你说delete p
时,针对于任何对象p
,你所说的是:
我郑重承诺不再触碰此内存地址!
现在,如果你再次调用new int
,堆可能会把那个内存地址还给你,也可能会给你另一个内存地址。但你只能在new
和delete
之间的时间访问由堆分配的内存。
鉴于此,这是什么意思?
delete p;
cout << *p << "\t" << p << "\n";
在C++中,这被称为“未定义行为”。C++规范有很多被声明为“未定义”的事情。当你触发未定义行为时,
任何事情都可能发生!*p
可能为0。
*p
可能是它曾经的值。
*p
的操作
可能会导致程序崩溃。
C++规范是您和编译器/计算机之间的合同。它说明了您可以做什么,以及系统如何响应。"未定义行为"是当您违反合同,即执行C++规范所说不应该执行的操作时发生的情况。此时,任何事情都可能发生。
当您调用
delete p
时,您告诉系统您已经
完成了对
p
的使用。通过再次使用它,您向系统
撒谎。因此,系统不再必须遵守任何规则,例如存储您想要存储的值。或继续运行。或不从您的鼻子中产生恶魔。或其他。
您违反了规则。您必须承担后果。
因此,
delete p
不等同于
*p = 0
。后者仅意味着“将0设置到
p
指向的内存中”。前者意味着“我已经完成了对由
p
指向的内存的使用,
在您告诉我可以使用之前,我不会再次使用它。”
std::string
,*p = 0
会如何工作? - ildjarn