2013-03-19 1 views
4

Я столкнулся с проблемой вызовом следующего кода:Использование зОго :: :: итератор деки (в STL C++) для поиска и удаления некоторых элементов

#include<deque> 
using namespace std; 

deque<int> deq = {0,1,2,3,4,5,6,7,8}; 

for(auto it = deq.begin(); it != deq.end(); it++){ 
    if(*it%2 == 0) 
     deq.erase(it); 
} 

что привело к ошибке сегментации. Изучив проблему, я обнаружил, что проблема заключается в том, что STL управляет итераторами для deques: если стираемый элемент ближе к концу deque, итератор, используемый для указания на стертый элемент, теперь укажет на NEXT элемент, но не предыдущий элемент, как vector::iterator. Я понимаю, что изменение условия цикла от it != deq.end() до it < deq.end() могло бы решить проблему, но мне просто интересно, есть ли способ обхода & стирать определенный элемент в deque в «стандартной форме», чтобы код мог быть совместим с другим типы контейнеров.

+2

Используйте 'std :: remove_if'. – chris

+0

Вы можете выполнять операции внутри функции (или объекта функции), назначенной std :: remove_if, тогда вы все равно можете использовать std :: remove_if (как предлагал @Fraser). Я предлагаю использовать общие алгоритмы вместо простого цикла, потому что цикл не достаточно ясен с вашим намерением. Кроме того, я думаю, что изменение и перемещение контейнера одновременно опасно. –

ответ

18

http://en.cppreference.com/w/cpp/container/deque/erase

Все итераторы и ссылки аннулируются [...]

Возвращаемое значение: итератора после последнего удаленного элемента.

Это общая закономерность, когда удаление элементов из контейнера STL внутри цикла:

for (auto i = c.begin(); i != c.end() ; /*NOTE: no incrementation of the iterator here*/) { 
    if (condition) 
    i = c.erase(i); // erase returns the next iterator 
    else 
    ++i; // otherwise increment it by yourself 
} 

Или, как chris упоминалось вы могли бы просто использовать std::remove_if.

10

Чтобы использовать erase-remove idiom, вы могли бы сделать что-то вроде:

deq.erase(std::remove_if(deq.begin(), 
         deq.end(), 
         [](int i) { return i%2 == 0; }), 
      deq.end()); 

Убедитесь, что #include <algorithm> сделать std::remove_if доступны.

+0

Спасибо, это тоже очень полезная информация! Но у меня есть некоторые дополнительные операции, связанные с элементами, которые нужно удалить, поэтому решение @syam подходит мне лучше. Спасибо, в любом случае! –

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