我正在玩内存动态分配,但我不明白。使用new
语句分配一些内存时,我应该能够使用delete
来销毁指针指向的内存。
但是当我尝试时,这个delete
命令似乎不起作用,因为指针指向的空间似乎没有被清空。
让我们以这个真正基本的代码为例:
#include <iostream>
using namespace std;
int main()
{
//I create a pointer-to-integer pTest, make it point to some new space,
// and fulfill this free space with a number;
int* pTest;
pTest = new int;
*(pTest) = 3;
cout << *(pTest) << endl;
// things are working well so far. Let's destroy this
// dynamically allocated space!
delete pTest;
//OK, now I guess the data pTest pointed to has been destroyed
cout << *(pTest) << endl; // Oh... Well, I was mistaking.
return 0;
}
有任何线索吗?
答案 0 :(得分:55)
是时候了解未定义的行为是什么。 :)
在C ++中,当你做一些非法/荒谬/坏/等的事情。标准经常说“它会导致不明确的行为”。这意味着从那时起,程序的状态完全无法保证,任何事情都可能发生。
在您执行上一次*(pTest)
时,您会得到未定义的行为。这是因为pTest
没有指向有效对象,并且取消引用这样的指针是未定义的。所以你所看到的是完全允许的:未定义的输出。
你所做的就是说“我完成了这个分配。”一旦你说过,你就不应该(实际上,不能)再检查或关心那个记忆。从某种程度上说,释放某些东西然后尝试使用它甚至没有概念意义;你说你已经完成了!
你的输出有点可预测:可能,你的操作系统只是说“好吧,谢谢你的记忆”,就是这样。它没有理由实际“重置”内存,或做任何特别的事情。当没有人(包括你自己的程序)没有使用它时,这确实是浪费时间。
但请记住,此输出完全未定义。不要尝试使用不存在的对象。也许更好的测试是:
#include <iostream>
struct foo
{
~foo()
{
std::cout << "foo is gone :(" << std::endl;
}
};
int main(void)
{
foo* f = new foo();
delete f; // you'll see that the object is destroyed.
}
虽然看起来你正在寻找内存本身会发生什么。请记住,摆脱内存然后尝试使用它是没有意义的,所以答案是:谁知道。这取决于您的特定平台,C ++并不关心。
答案 1 :(得分:10)
调用delete会将内存区域标记为空闲。它不需要重置其旧值。
建议在调用delete后将指针设置为0:
delete pTest;
pTest = 0;
答案 2 :(得分:5)
delete operator调用对象的析构函数并释放先前分配给该对象的内存。 它不会影响指向已删除对象的指针变量。
因此,当取消引用指向被破坏对象的指针时,您将遇到麻烦。
答案 3 :(得分:5)
答案是表现。
这是一个很好的调试辅助工具,用无效值(0xCCCCCCCC
,0xDEADDEAD
等)填充所有释放的内存,以捕获尝试使用过时指针到已释放的内存。
但修改释放的内存会花费CPU时间,因此出于性能原因,操作系统只会将释放的内存块添加到其“空闲”列表中,并保留内容完整。
答案 4 :(得分:2)
取消引用指向释放内存的指针是未定义的行为。
很多时候它会起作用,因为new
提供的内存通常是分配器管理的更大块分配内存的一部分。当你调用delete
时,它会调用相关的析构函数并将内存标记为空闲,这通常意味着“可以重用”。因此,查看该内存,您将找到调用delete
之前的相同数据,或者在new
调用后重新分配该内存块时的其他一些数据。
请注意,没有任何内容禁止new
/ delete
分配器作为操作系统虚拟内存函数的瘦包装器,因此当相对于页面的所有已分配块已被解除分配时,整个页面被释放,任何访问它的尝试都会导致地址违规。
TL,DR版本:不要指向释放内存的deference指针:它有时会工作,有时会给你回垃圾,有时会触发访问冲突。
如果你正在做这种错误,立即注意的一个好方法是在删除它们指向的内存之后将指针设置为NULL:如果你的代码试图取消引用NULL指针,几乎任何系统都会这样做应用程序崩溃,所以这些故障不会被忽视。
答案 5 :(得分:1)
它可以引用任何一块映射内存。或者可能是未映射的内存,具体取决于程序执行的时间,内存分配的详细信息,以及库是否稍后将内存返回给操作系统......
如果delete
实际清除了所有正在删除的内存,程序将花费更长的时间运行,因为它们浪费了大量时间擦洗内存,无论如何迟早都可能会被覆盖。它可能适合调试,但在生产使用中,没有太多要求实际清理内存内容。 (当然,加密密钥是一个很好的例外;在调用delete
或free
之前擦除这些密钥是一个好主意。)
答案 6 :(得分:1)
破坏数据意味着什么?我想它可以把它归零,但为什么要这么麻烦?当我们从环境中获取它时,它会被认为是脏的,那么为什么要在返回之前清理它呢?我们不关心其中的内容,因为我们放弃了阅读它的权利。至于为什么删除不会将指针本身清零:
答案 7 :(得分:1)
只是一个简单的例子来说明可能发生的事情,以及未定义的内容 一些人提到的行为意味着。
如果我们在打印之前添加两行额外的代码:
delete pTest;
int *foo = new int;
*foo = 42;
cout << *pTest << endl;
pTest的打印值很可能是3,就像你的情况一样。 但是,打印值也可能是42.当pTest指针被删除时, 它的记忆被释放了。因此,foo指针可能会出现这种情况 指向pTest之前指向的内存中的相同位置 删除。
答案 8 :(得分:0)
对指针调用 delete 会将其指向的内存块标记为“空闲内存”。它不会立即销毁内存中的项目。 'items' 只有在进程返回后才会被销毁,因为'delete' 被用于指向该内存块的指针。如果不使用 'delete',它会永远停留在那里,导致内存泄漏。
要解决您的问题,只需:
delete pTest;
pTest=NULL;