4

另一个 C++ 指针删除问题在以下示例中:

class Foo {
public:
    int *p;
    ~Foo() {
        delete p; p = NULL;
    }
};

Foo *f1 = new Foo();
Foo *f2 = new Foo();
f1->p = new int(1);
f2->p = f1->p;
delete f2; // ok
delete f1; // no error?

为什么调用“delete f1”时没有出错?我不是两次删除了同一个地址(*p)吗?

如果我直接删除最后两行代码中的指针,我会得到错误。

delete f2->p; // ok
delete f1->p; // error!! *** glibc detected *** double free or corruption (fasttop) ***
4

5 回答 5

5

这是一件非常糟糕的事情。然而,C++ 不一定会在这里做任何事情。这是“未定义”的行为。这并不意味着它会崩溃,但它很可能会导致糟糕的事情(tm)发生。

编辑:此外,在您的第二个示例中,它崩溃的事实只是“未定义”行为的一部分。至于会有什么反应,还没有定论。

于 2010-10-15T09:34:24.277 回答
3

为什么调用“delete f1”时没有出错?我不是两次删除了同一个地址(*p)吗?

是的,您确实删除了该对象两次。

但是,其结果是Undefined Behavior。这可能会导致运行时系统捕获错误并弹出消息,但也可能导致您的 HD 被格式化,讨厌的鼻恶魔在办公室里追逐您,让您的同事高兴,或者您或者你的女朋友怀孕了。或者它也可能看起来“工作”,无论在这种情况下意味着什么。

于 2010-10-15T10:51:54.470 回答
3

相信我,你不想那样做。

看一下boost::shared_ptr:它允许您以优雅的方式处理指针,而不必太在意它们的删除。

class Foo {
public:
    boost::shared_ptr<int> p;
};

Foo *f1 = new Foo();
Foo *f2 = new Foo();
f1->p.reset(new int(1));
f2->p = f1->p;
delete f2; // ok
delete f1; // no error and its guaranteed !

如果您不想使用boost,一些编译器已经提供std::tr1::shared_ptr了具有相似语义的。

于 2010-10-15T09:38:16.360 回答
1

如果要使用多个指向同一内存的指针,请将它们封装在 中boost::shared_ptr,这将确保底层内存在最后一次引用超出范围之前不会被 delete-d。

#include <boost/shared_ptr.hpp>

class Foo {
public:
    boost::shared_ptr<int> p;
    ~Foo() {
      p.reset();
    }
};

Foo *f1 = new Foo();
Foo *f2 = new Foo();
f1->p.reset(new int(1));
f2->p = f1->p;
delete f2; // ok
delete f1; // no error
于 2010-10-15T09:38:36.683 回答
0

当然,双重删除是未定义的行为。如果在调试和发布版本之间,它也可能会发生变化。其他人已经向你指出了boost::shared_ptr诸如此类的好处。

但是,还需要提及如何可靠地找到这些错误:

在valgrind中运行您的程序。

在 Windows 上,purify是 valgrind 的较旧的商业版本。

于 2010-10-15T12:37:45.000 回答