Должны ли мы удалять до или после стирания указатель в векторе? - PullRequest
5 голосов
/ 17 сентября 2010

Должны ли мы удалять до или после erase. Я понимаю, что оба в порядке. Это правильно?

Кроме того, есть ли случай, когда мы не захотим удалить элемент при его удалении? Я считаю, что должно быть, в противном случае erase будет рад взять на себя ответственность.

std::vector<foo*> bar;
...
for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); itr++)
{
   delete (*itr);  //before OR
   bar.erase(itr);
   delete (*itr);  //after???
}

Ответы [ 5 ]

10 голосов
/ 17 сентября 2010

"itr" должен использоваться следующим образом;

for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); )
{
   delete (*itr);
   itr = bar.erase(itr);
}

Однако я бы предпочел сначала удалить все элементы, а затем очистить вектор;

for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); ++itr)
   delete (*itr);
bar.clear();
4 голосов
/ 17 сентября 2010

Использование итератора для удаления элемента делает его недействительным.Вы должны удалить элемент, прежде чем он будет удален.

Вы также должны использовать возвращаемое значение из стирания для следующей итерации цикла.

3 голосов
/ 17 сентября 2010

Кроме того, есть ли случай, когда мы не захотим удалить элемент при его удалении?

Как вектор мог узнать, если кому-то еще нужны объекты, на которые он указывает?Как он мог даже знать, что пуанты хранятся в куче?Вполне возможно иметь указатели на статические или автоматические объекты в векторе или даже висячие указатели.

C ++ 0x позволяет вам выразить, что вектор должен владеть пуантами:

std::vector<std::unique_ptr<foo>> vec;

Теперь вам не нужно ничего удалять вручную.Стирая уникальные указатели, удаляются и их соответствующие указатели.Контейнеры собственных указателей очень редки в современном C ++.

Если у вас нет компилятора C ++ 0x, вы можете использовать вместо него std::vector<boost::shared_ptr<foo> > или boost::ptr_vector<foo>.Современные компиляторы поставляют shared_ptr в пространство имен std::tr1 или std, если вы #include <memory>.

2 голосов
/ 17 сентября 2010

Природа вектора, при котором стирается первый элемент, заставляет весь массив сместиться вперед, чтобы уменьшить эту операцию, попробуйте следующее:

std::vector<foo*> v1;
//...
while(!v1.empty())
{
    delete v1.back();
    v1.pop_back( );
}

Кстати, этот метод не делает недействительными никакие итераторы (только при удалениитовар)

1 голос
/ 17 сентября 2010

Выполнение erase сделает недействительным итератор vector.Так что *iter вызовет неопределенное поведение.Следовательно, вам нужно сделать delete после erase.Кроме того, вы не можете erase элементы из vector во время итерации по нему (по той же причине iter становится недействительным, поэтому iter++ недопустимо).В этом случае вы можете удалить вызов erase из цикла и сделать clear вектора вне цикла.

...