Да, удаление Foo*
из контейнера уничтожает Foo*
, но не освобождает Foo
. Уничтожение необработанного указателя всегда является запретом. Иначе и быть не может! Позвольте мне назвать вам несколько причин, почему.
Класс хранения
Удаление указателя имеет смысл только в том случае, если указатель был фактически выделен динамически, но как среда выполнения может узнать, так ли это при уничтожении переменной указателя? Указатели также могут указывать на статические и автоматические переменные, и удаление одной из этих переменных приводит к неопределенному поведению.
{
Foo x;
Foo* p = &x;
Foo* q = new Foo;
// Has *q been allocated dynamically?
// (The answer is YES, but the runtime doesn't know that.)
// Has *p been allocated dynamically?
// (The answer is NO, but the runtime doesn't know that.)
}
Свисающие указатели
Невозможно выяснить, выпускался ли указатель в прошлом. Удаление одного и того же указателя дважды приводит к неопределенному поведению. (После первого удаления он становится свисающим указателем.)
{
Foo* p = new Foo;
Foo* q = p;
// Has *q already been released?
// (The answer is NO, but the runtime doesn't know that.)
// (...suppose that pointees WOULD be automatically released...)
// Has *p already been released?
// (The answer WOULD now be YES, but the runtime doesn't know that.)
}
Неинициализированные указатели
Также невозможно определить, была ли вообще инициализирована переменная-указатель. Угадайте, что происходит, когда вы пытаетесь удалить такой указатель? И снова ответ - неопределенное поведение.
{
Foo* p;
// Has p been properly initialized?
// (The answer is NO, but the runtime doesn't know that.)
}
Динамические массивы
Система типов не делает различий между указателем на отдельный объект (Foo*
) и указателем на первый элемент массива объектов (также Foo*
). Когда переменная-указатель уничтожается, среда выполнения не может понять, следует ли освободить указатель через delete
или через delete[]
. Освобождение через неправильную форму вызывает неопределенное поведение.
{
Foo* p = new Foo;
Foo* q = new Foo[100];
// What should I do, delete q or delete[] q?
// (The answer is delete[] q, but the runtime doesn't know that.)
// What should I do, delete p or delete[] p?
// (The answer is delete p, but the runtime doesn't know that.)
}
Резюме
Поскольку среда выполнения не может сделать ничего разумного с указателем, уничтожение переменной-указателя всегда не работает. Ничего не делать определенно лучше, чем вызывать неопределенное поведение из-за неосведомленного предположения :-)
Совет
Вместо необработанных указателей рассмотрите возможность использования интеллектуальных указателей в качестве типа значения вашего контейнера, потому что они берут на себя ответственность за освобождение указателя, когда он больше не нужен. В зависимости от ваших потребностей используйте std::shared_ptr<Foo>
или std::unique_ptr<Foo>
. Если ваш компилятор еще не поддерживает C ++ 0x, используйте boost::shared_ptr<Foo>
.
Никогда, повторяю, НИКОГДА не используйте std::auto_ptr<Foo>
в качестве типа значения контейнера.
person
fredoverflow
schedule
23.11.2010