Я искал StackOverflow, но не мог найти ответ на этот вопрос.
Предположим, что у меня есть a std::vector<Day *> vector_day
- это - вектор указателей на Day
объект. Теперь я push_back
кому: vector_day
много элементов:
vector_day.push_back(new Day(12));
vector_day.push_back(new Day(99));
vector_day.push_back(new Day(71));
...
Теперь в какой-то момент мне больше не нужно vector_day
. Что правильный путь состоит в том, чтобы освободить память?
Это это корректный путь:
for (std::vector<Day *>::iterator i = vector_day.begin(); i != vector_day.end(); ++i) {
delete *i;
}
Разве это не делает недействительным вектор на каждом удалении? Я очень смущен.
Лучший способ - не помещать указатели в вектор в первую очередь, если в этом нет крайней необходимости.
Но если вам действительно нужен вектор указателей, то способ, которым вы это делаете, будет прекрасным (но .clear ()
вектор послесловия, если он не будет немедленно уничтожен , так что он не заполнен висячими указателями)
Оператор
delete *it;
не влияет на итератор. Он не изменяет итератор, не делает итератор недействительным и не удаляет указатель, на который ссылается итератор, из коллекции. Все, что он делает, - это освобождает память, на которую указывает указатель, на который указывает итератор. Сам указатель необходимо удалить из коллекции отдельно.
Boost ptr_vector на помощь!
Делает именно то, что вам нужно, без необходимости итерации и удаления содержимого std::vector
Another C++ way to do this is to define a helper struct:
struct delete_ptr { // Helper function to ease cleanup of container
template <typename P>
void operator () (P p) {
delete p;
}
};
and then use the algorithms:
std::for_each(vector_day.begin(), vector_day.end(), delete_ptr());
vector_day.clear();
В целом в C ++ вы должны как можно больше скрывать управление памятью, чтобы избежать ошибок памяти. Если вы не копируете много указателей и не заботитесь о производительности, я бы просто использовал shared_ptr.
Это часть стандарта TR1, доступная в большинстве современных компиляторов C ++ из коробки ( http://anteru.net/2008/09/01/260/ ) и отлично подходит для пожара. и забудьте об управлении памятью.
Операции, добавляющие или удаляющие элементы из массива, могут сделать итераторы недействительными, проверьте документацию на предмет конкретных правил для различных типов контейнеров. С помощью delete
вы воздействуете на данные, содержащиеся в элементах массива, а не на его форму. Итераторы перемещаются по форме контейнера, им не важно его содержимое.
Вероятно, вам следует использовать какой-то управляемый указатель, скорее всего, общий указатель.
Если вы удалите вектор, пока кто-то еще удерживает один из этих указателей, вы получите очень неприятное поведение, если они попытаются разыменовать его. Общий указатель избавит вас от этой головной боли.
Если вы можете гарантировать, что ничто другое не будет ссылаться на указатели после удаления вектора, вы все равно можете воспользоваться автоматическим указателем. Он будет управлять освобождением для вас, когда вектор будет уничтожен. Накладные расходы минимальны, и это значительно облегчает вашу жизнь.
Ничего страшного. Вы удаляете * i
(объект, на который указывает элемент вектора), а не i
(элемент вектора), поэтому вектор не становится недействительным.
См. этот вопрос для случая, когда разработчик также хотел удалить все i
s, и решение для этого ( vector_day.clear ()
) после цикла.
Вот удобный класс, который я написал некоторое время назад, когда занимался той же проблемой. Я преобразовывал некоторый код из старых векторов и списков на основе RogueWave в векторы и списки на основе STL и нуждался в каком-то способе эмуляции метода clearAndDestroy () RW для списков указателей. Метод clearAndDestroy () можно переопределить для обработки различных типов структур (я включил сюда только вектор для краткости).
class StlUtils
{
public:
/**
* This method provides a templated way to destroy a std::vector
* full of pointers. It is basically a replacement for the RW
* vector class' clearAndDestroy methods. The list argument is
* returned empty.
*
* @param list the list of pointers to be destroyed.
*/
template<class T> static void clearAndDestroy(
std::vector<T*> &itemList)
{
for_each(itemList.begin(), itemList.end(),
stl_deleter<T>());
itemList.clear();
}
private:
/**
* Templated member function for use with the clearAndDestroy()
* method. It provides the method needed by for_each to do the
* actual deletion.
*/
template<class T> struct stl_deleter
{
void operator() (T* x) {
if (x != NULL)
delete x;
}
};
};
Прежде всего, вы переключились с i
на it
, но я предполагаю, что это всего лишь опечатка.
Но ответить на ваш квест - нет, это нормально. Вы не меняете it
, вы меняете * it
.