итератор списка не может быть увеличен - PullRequest
6 голосов
/ 13 октября 2008

У меня есть старый проект, который был построен с использованием Visual Studio 2003, и я недавно перекомпилировал его с vs2005. Однако во время выполнения я получаю следующую ошибку:

список итераторов не увеличивается

Я проследил программу до этой функции:

void InputQueue::update()
{
    list<PCB>::iterator iter;
    list<PCB>::iterator iterTemp;
    for(iter = begin(); iter != end(); iter++)
    {
        if(iter->arrivalTime == 0)
        {           
            ReadyQueue::getInstance()->add(*iter);
            iterTemp = iter;
            iter++;
            erase(iterTemp);
        }
    }
}

Я не эксперт по C ++, и это настолько, насколько отладчик VS достал меня. Может кто-нибудь объяснить мне, в чем проблема?

Спасибо

Ответы [ 8 ]

14 голосов
/ 13 октября 2008

Я бы переписал ваш цикл так:

while (iter != end())
{
  if (iter->arrivalTime == 0)
  {
    ReadyQueue::getInstance()->add(*iter);
    iter = erase(iter);
  }
  else
  {
    ++iter;
  }
}

Теперь вы корректно просматриваете список, проверяя каждый индекс.

9 голосов
/ 13 октября 2008

Обратите внимание, что если iter->arrivalTime == 0, то итератор списка увеличивается на два: один раз перед удалением элемента и еще раз в конце цикла.

Если удаляемый элемент является последним в списке, это, очевидно, будет работать неправильно. Смею сказать, что он никогда не работал правильно даже в VS2003, но VS2005 предупреждает вас об этом лучше. : -)

Помните, что итерация мимо end() не определена. Абсолютно все может произойти, например, сбой программы или (в данном случае) сообщение об ошибке.

1 голос
/ 06 ноября 2013

Основная причина - "list.erase ()" изменит итератор. Правильная запись для цикла "for":

   for (list<CMessage*>::iterator it=que.begin(); it!=que.end(); ++it)
   {
    if(m_type == (*it)->m_type)
    {
        delete *it;
        it=que.erase(it); //"list.erase()" will change the iterator!!!
        if(it==que.end()) break; //Check again!!!
        //still has side effect here. --it?
    }
   }

Но у него все еще есть побочный эффект, поэтому решение Марка будет лучшим.

1 голос
/ 13 октября 2008

Я просто опущу несколько строк вашего кода, чтобы показать, в чем проблема:

    for(iter = begin(); iter != end(); iter++) // ***
    {
        if(iter->arrivalTime == 0)
        {                       

                iter++; // ***

        }
    }

В двух строках, помеченных ***, вы увеличиваете итератор. Проблема в том, что во второй из двух строк вы не проверяете, не дошли ли вы до конца контейнера. Фактически, если вы попадаете во внутренний цикл, вы увеличиваете его в два раза, а проверяете, можете ли вы увеличить его один раз.

Одно из решений - проверить, находитесь ли вы на end(), прежде чем делать второй шаг, но мне кажется, что вы пытаетесь выполнить ту же операцию, что и я в мой вопрос некоторое время назад делать с фильтрацией элементов из контейнера (карта в этом случае, но то же самое относится к большинству контейнеров STL).

0 голосов
/ 13 октября 2008

Могу ли я предложить более простой алгоритм?

Свободную функцию std::remove_if можно использовать для разбиения вашего списка на 2 элемента, которые соответствуют или не соответствуют предикату (то есть прибытие / время == 0). Возвращает итератор, разделяющий диапазоны. Затем вы можете позвонить ReadyQueue::getInstance()->add(subrange_begin, subrange_end) (у вас есть эта перегрузка, верно?) и впоследствии стереть поддиапазон.

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

0 голосов
/ 13 октября 2008

Если вы получаете «несовместимый итератор списка», это возможно потому, что внутри вашего «ReadyQueue :: getInstance () -> add (* iter);» вы изменяете что-то в * iter, из-за чего алгоритм хэширования возвращает значение для стирания, отличное от значения, которое было при вставке.

0 голосов
/ 13 октября 2008

Это только знак, но важный.

Я полагаю, вы наследуете от std::ist<PCB>. Я должен сказать: унаследование для повторного использования функциональности не всегда оказывалось хорошим для меня. Но так как вы также «наследуете» проект, с этим ничего не поделаешь ...

0 голосов
/ 13 октября 2008

Я верю, что Крис прав. Однако другая проблема может быть связана с тем, что вы назначаете итератору. Гарантированно присваиваются итераторы списка? Не смотря на стандарт, я так не думаю, потому что в документации SGI итераторов нигде не упоминается присваиваемость.

...