为什么不删除任何东西?

时间:2010-07-19 10:55:55

标签: c++ memory new-operator delete-operator

我正在玩内存动态分配,但我不明白。使用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;  
}  

有任何线索吗?

9 个答案:

答案 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)

答案是表现

这是一个很好的调试辅助工具,用无效值(0xCCCCCCCC0xDEADDEAD等)填充所有释放的内存,以捕获尝试使用过时指针到已释放的内存。

但修改释放的内存会花费CPU时间,因此出于性能原因,操作系统只会将释放的内存块添加到其“空闲”列表中,并保留内容完整。

答案 4 :(得分:2)

取消引用指向释放内存的指针是未定义的行为。

很多时候它会起作用,因为new提供的内存通常是分配器管理的更大块分配内存的一部分。当你调用delete时,它会调用相关的析构函数并将内存标记为空闲,这通常意味着“可以重用”。因此,查看该内存,您将找到调用delete之前的相同数据,或者在new调用后重新分配该内存块时的其他一些数据。

请注意,没有任何内容禁止new / delete分配器作为操作系统虚拟内存函数的瘦包装器,因此当相对于页面的所有已分配块已被解除分配时,整个页面被释放,任何访问它的尝试都会导致地址违规。

TL,DR版本:不要指向释放内存的deference指针:它有时会工作,有时会给你回垃圾,有时会触发访问冲突。

如果你正在做这种错误,立即注意的一个好方法是在删除它们指向的内存之后将指针设置为NULL:如果你的代码试图取消引用NULL指针,几乎任何系统都会这样做应用程序崩溃,所以这些故障不会被忽视。

答案 5 :(得分:1)

它可以引用任何一块映射内存。或者可能是未映射的内存,具体取决于程序执行的时间,内存分配的详细信息,以及库是否稍后将内存返回给操作系统......

如果delete实际清除了所有正在删除的内存,程序将花费更长的时间运行,因为它们浪费了大量时间擦洗内存,无论如何迟早都可能会被覆盖。它可能适合调试,但在生产使用中,没有太多要求实际清理内存内容。 (当然,加密密钥是一个很好的例外;在调用deletefree之前擦除这些密钥是一个好主意。)

答案 6 :(得分:1)

破坏数据意味着什么?我想它可以把它归零,但为什么要这么麻烦?当我们从环境中获取它时,它会被认为是脏的,那么为什么要在返回之前清理它呢?我们不关心其中的内容,因为我们放弃了阅读它的权利。至于为什么删除不会将指针本身清零:

http://www2.research.att.com/~bs/bs_faq2.html#delete-zero

答案 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;