Многократное C ++ удаление памяти, указанной несколькими объектами - PullRequest
4 голосов
/ 15 октября 2010

Другой вопрос удаления указателя 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) дважды?

Если я напрямую удаляю указатели в последних 2 строках кода, я получу ошибку.

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

Ответы [ 5 ]

5 голосов
/ 15 октября 2010

Это ОЧЕНЬ плохо. Однако C ++ не обязательно будет делать что-либо здесь. Это «неопределенное» поведение. Это не значит, что он потерпит крах, но, скорее всего, он вызовет плохое дерьмо (тм).

Edit: Более того, в вашем втором примере тот факт, что он падает, является лишь частью "неопределенного" поведения. Неизвестно, какой будет реакция.

3 голосов
/ 15 октября 2010

Почему я не получил ошибку при вызове "delete f1"? я не удалил один и тот же адрес (* p) дважды?

Да, вы действительно удалили этот объект дважды.

Однако результатом этого является Неопределенное поведение . Это может привести к тому, что система во время выполнения поймает ошибку и выдаст сообщение, но это также может привести к тому, что ваш HD будет отформатирован, противные носовые демоны будут преследовать вас по офису, чтобы доставить вам удовольствие коллеги по работе, или вы или ваша девушка забеременеете. Или тогда это может также «работать», что бы это ни значило в данном случае.

3 голосов
/ 15 октября 2010

Поверь мне, ты не хочешь этого делать.

Взгляни на 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 с аналогичной семантикой.

1 голос
/ 15 октября 2010

Если вы хотите использовать несколько указателей на одну и ту же память, инкапсулируйте их в boost::shared_ptr, что гарантирует, что базовая память не будет удалена-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
0 голосов
/ 15 октября 2010

Конечно, двойное удаление - неопределенное поведение.Это также может измениться, если между отладочной и релизной сборками.Другие указали вам на доброту boost::shared_ptr и тому подобное.

Однако полезно также упомянуть, как вы можете надежно находить такого рода ошибки:

Запустите вашу программу в valgrind .

В Windows cleany является более старым коммерческим аналогом valgrind.

...