2012-04-18 4 views
2

Я хочу удалить некоторый итератор из вектора, так что это то, что у меня есть сейчас.C++ стереть std :: vector.end() при переходе по всем итераторам

void function(std::vector <class*> & vector) 
{ 
    std::vector <class*>::iterator it; 
    for(it = vector.begin(); iter != vector.end(); ++iter) 
     { 
      if(it->value == 1) 
       vector.erase(it); 
     } 
    Display(vector); 
    return; 
} 

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

Спасибо.

+0

Попробуйте использовать его = vector.erase (it), но не увеличивайте его при назначении из функции стирания, поскольку в противном случае вы пропустите пункты –

+0

Стандартная библиотека не гарантирует, что итераторы действительны, когда коллекция изменяется каким-либо образом. Хорошей новостью является то, что всегда есть способы справиться с этим и, как правило, более кратким образом, например. см. ответ Илисара. –

+0

@DeepYellow: стандарт дает некоторые гарантии для некоторых операций над некоторыми контейнерами; в этом случае он гарантирует, что итераторы и ссылки на элементы * до * точки стирания остаются vaild. Очевидно, что итераторы и ссылки на стертый элемент всегда будут признаны недействительными для любого контейнера. –

ответ

5
for (it = vector.begin(); it != vector.end();) 
{ 
    if (it->value == 1) 
     it = vector.erase(it); 
    else 
     ++it; 
} 

Но в этом случае, вы должны на самом деле просто использовать std::remove_if с соответствующим предикатом.

+0

Спасибо за ответ. Я пробовал свой путь, но почему-то я не знаю, почему после стирания, «++ it» не увеличивает итератор. – Derek

+0

@ Derek: Я не понимаю, что вы там говорите. С кодом, который я дал, когда элемент стирается, я * не * увеличиваю итератор. Вместо этого я устанавливаю его в возвращаемое значение функции стирания, которое является следующим элементом после стираемого (которое теперь находится в том положении, в котором было стерто ранее занятое). Поэтому я не знаю, что вы подразумеваете под своим заявлением. Просьба уточнить. –

+0

Моя вина за непонятность. Стирание идет хорошо, и итератор будет возвращен в качестве следующего элемента. Но в следующем цикле цикла for выполняется «++ it», но я обнаружил, что после этого итератор не увеличивается. – Derek

4

Другой подход:

vector.erase(std::remove_if(vector.begin(), vector.end(), boost::bind(&class::value, _1) == 1), vector.end()); 

boost::bind, вероятно, может быть заменен std::bind, если он доступен.

+1

'std :: bind' не поддерживает' operator == 'таким образом - это расширение Boost. – ildjarn

+0

А, это приятно знать :) – Ylisar

-1

Плохая идея стирать из вектора, итерации по нему. Просто отфильтруйте его.

void function(std::vector <class*> & vector) 
{ 
    std::vector <class*>::iterator from= vector.begin(); 
    std::vector <class*>::iterator to= from; 
    for(; from != vector.end(); ++from) 
     { 
      if((*from)->value == 1) continue; 
      // it should be (*from) or use boost::ptr_vector 
      *(to++)=*from; 
     } 
    vector.erase(to, vector.end()); 
    Display(vector); 
    return; 
} 

Это функциональность, точно идентичная коду Ylisar. ИМХО это лучше всего для вектора, если вы всегда что-то удаляете, но если удаление очень редко (для всего одного вектора), используйте версию Бенджамина Линдли.

Независимо от оптимизации может быть, вы можете фильтровать только если он у вас есть что-то, чтобы стереть:

void function(std::vector <class*> & vector) 
{ 
    std::vector <class*>::iterator to= vector.begin(); 
    for(; to != vector.end(); ++to) 
    { 
     if((*to)->value == 1) 
     { 
     std::vector <class*>::iterator from=to; 
     for(++from; from != vector.end(); ++from) 
     { 
      if((*from)->value == 1) continue; 
      *(to++)=*from; 
     } 
     vector.erase(to, vector.end()); 
     break; 
     } 
    } 
    Display(vector); 
    return; 
} 

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

void function(std::vector <class*> & vector) 
{ 
    std::vector <class*>::iterator to= vector.begin(); 
    std::vector <class*>::iterator from=vector.end(); 
    if(to == from) return; 
    for(;;) 
    { 
     if((*to)->value == 1) // need skip value from begin 
     { 
     for(--from; from != to; --from) 
     { 
      if((*from)->value == 1) continue; // need skip value from end 
      *to=*from; 
      ++to; // copied, move to next 
     } 
     } 
     else 
     { 
     ++to; //preserved, move to next 
     } 
     if(to == from) 
     { 
     vector.erase(to, vector.end()); 
     break; 
     } 
    } 
    Display(vector); 
    return; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^