为什么我必须在“原始”指针上调用delete?

时间:2012-01-10 15:53:49

标签: c++ pointers memory delete-operator

我想知道为什么在下面的代码中第一次删除不会释放内存:

#include <list>
#include <stdio.h>

struct abc {
    long a;

    abc() {
        puts("const");
    }
    ~abc() {
        puts("desc");
    }
};

int main() {

    std::list<abc*> test;

    abc* pA = new abc;
    printf("pA: 0x%lX\n", (unsigned long int)pA);
    test.push_back(pA);

    abc* pB = test.back();

    printf("pB: 0x%lX\n", (unsigned long int)pB);
    delete pB; // just ~abc()

    test.pop_back();

    delete pA; // ~abc() and free (works)

    puts("before double-free");

    delete pA; // ~abc() and second free (crash)

    return 0;
}

输出是:

const
pA: 0x93D8008
pB: 0x93D8008
desc
desc
before double-free
desc
*** glibc detected *** ./test: double free or corruption (fasttop): 0x093d8008 ***
...

我用free()尝试了同样的行为。

4 个答案:

答案 0 :(得分:4)

delete pA; // ~abc() and free (works)

puts("before double-free");

delete pA; // ~abc() and second free (crash)

编写delete后,这些delete pB语句。你错误地认为delete pB只调用了析构函数。不,它调用析构函数并释放内存。

此外,由于您已经编写了delete pB,接下来的两个delete表达式会调用undefined behavior,这意味着任何事情都可能发生:程序可能可能崩溃!

看看这些主题:

答案 1 :(得分:2)

您的第一次删除会将指针呈现为无效状态。因此,使用该指针现在会导致未定义的行为。

int* p = new int;
delete p;
delete p; //undefined behaviour

标准保证这是正常的(如第一条评论中所指出的):

int* p = new int;
delete p;
p = 0;
delete p; //fine

答案 2 :(得分:1)

首先,您不能free使用new分配的内存,您必须使用delete

其次,仅仅因为glibc没有立即检测到双重免费,你如何知道 delete pB;没有释放它?这就是delete的作用,并且从您自己的日志记录中,您每次都将相同的地址传递给delete

第三:你究竟想要完成什么?

答案 3 :(得分:1)

这只是你的编译器/平台的一个独立性,你必须在delete抱怨之前在pA上调用glibc两次...例如,在我当前的平台上,即OSX 10.6.8使用gcc版本i686-apple-darwin10-gcc-4.2.1,我得到以下输出:

const
pA: 0x100100080
pB: 0x100100080
desc
desc
test(14410) malloc: *** error for object 0x100100080: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap

因此,您可以在delete上看到对pA的第一次调用,由于您未将指针设置为NULL或{{1},因此标准会导致未定义的行为在我的平台上通过C ++运行时尝试释放已经释放的内存,确实被抓住了。

由于双删除的结果是“未定义的行为”,因此实际上取决于实现和平台的发生。

如果通过使用0标志进行编译来使用针对glibc内存一致性检查程序的链接,则可以更快地检测分配/释放内存错误。