Удалить элемент из вектора во время итерации? - PullRequest
46 голосов
/ 17 января 2011

У меня есть вектор, который содержит элементы, которые являются активными или неактивными. Я хочу, чтобы размер этого вектора оставался небольшим из-за проблем с производительностью, поэтому я хочу, чтобы элементы, помеченные как неактивные, были удалены из вектора. Я пытался сделать это во время итерации, но я получаю сообщение об ошибке «несовместимые векторные итераторы».

vector<Orb>::iterator i = orbsList.begin();

    while(i != orbsList.end()) {
        bool isActive = (*i).active;

        if(!isActive) {
            orbsList.erase(i++);
        }
        else {
            // do something with *i
            ++i;
        }
    }

Ответы [ 8 ]

61 голосов
/ 17 января 2011

Самый читаемый способ, которым я занимался в прошлом, это использовать std::vector::erase в сочетании с std::remove_if.В приведенном ниже примере я использую эту комбинацию для удаления любого числа, меньшего 10, из вектора.

( Для не-C ++ 0x, вы можете просто заменить лямбду ниже на свой собственный предикат:)

// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));

// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(), 
                       [](int i) { return i < 10; }), v.end());
45 голосов
/ 27 октября 2012

Я согласен с ответом Уилкса. Вот реализация:

// curFiles is: vector < string > curFiles;

vector< string >::iterator it = curFiles.begin();

while(it != curFiles.end()) {

    if(aConditionIsMet) {

        it = curFiles.erase(it);
    }
    else ++it;
}
15 голосов
/ 17 января 2011

Вы можете сделать это, но вам придется немного переставить ваш while(), я думаю.Функция erase() возвращает итератор для элемента, следующего после стертого: iterator erase(iterator position);.Цитирование из стандарта от 23.1.1 / 7:

Итератор, возвращенный из a.erase (q), указывает на элемент, следующий сразу за q до удаления элемента.Если такого элемента не существует, возвращается a.end ().

Хотя, возможно, вам следует использовать идиому Erase-remove .

4 голосов
/ 31 июля 2013

Если кому-то нужно работать с индексами

vector<int> vector;
for(int i=0;i<10;++i)vector.push_back(i);

int size = vector.size();
for (int i = 0; i < size; ++i)
{
    assert(i > -1 && i < (int)vector.size());
    if(vector[i] % 3 == 0)
    {
        printf("Removing %d, %d\n",vector[i],i);
        vector.erase(vector.begin() + i);
    }

    if (size != (int)vector.size())
    {
        --i;
        size = vector.size();
        printf("Go back %d\n",size);
    }
}
2 голосов
/ 04 апреля 2019

erase возвращает указатель на следующее значение итератора (аналогично Vassilis):

vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{   if(condition)
        mit = myVec.erase(mit);
    else
        mit++;
}
2 голосов
/ 17 января 2011

Возможно, вы захотите использовать std::list вместо std::vector для вашей структуры данных.Безопаснее (меньше подвержено ошибкам) ​​использовать при объединении стирания с итерацией.

1 голос
/ 17 января 2011

Как они сказали, итераторы вектора становятся недействительными на vector::erase() независимо от того, какую форму приращения итератора вы используете.Вместо этого используйте целочисленный индекс.

1 голос
/ 17 января 2011

Удаление элементов из середины вектора сделает недействительными все итераторы для этого вектора, поэтому вы не можете сделать это ( обновление : без обращения к совету Уилкса).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...