Странное поведение неконстантного итератора списка в переполнении стека

У меня есть код:

it = tableAndHand.begin();
while(++it != tableAndHand.end()) {
if(*it == *(--it)) {
++cardCount;
++it;
} else {
cardCounts1.insert(pair<int,int>(cardCount,*it));
while(cardCount > 1) {
it = tableAndHand.erase(--it);
--cardCount;
}
++it;
}
}
cardCounts1.insert(pair<int,int>(cardCount,*(--it)));
while(cardCount > 1) {
it = tableAndHand.erase(--it);
--cardCount;
}

tableAndHand — это список из 7 значений при запуске, и я получаю ошибку сегментации в этом проблемном месте после стирания некоторых значений, почему это так?

Значения в списке сортируются, и в списке {0, 0, 0, 1, 1, 1, 2} происходит сбой где-то с итерациями 1 (после правильного удаления 2 0, поэтому размер списка уже равен 5).

Я просто хочу сохранить количество уникальных значений в карту cardCounts1 и удалить повторяющиеся значения из списка, что не так в моем алгоритме?

РЕДАКТИРОВАТЬ: похоже, что проблема была (* it == * (- it)) не оценивается слева направо, хотя я не могу найти оценку «==» в статьях об операторах на cplusplus.com и некоторых другие сайты говорят, что он оценивается слева направо. Какая-нибудь хорошая ссылка об этом?

EDIT2: ОК, это работает, я забыл назначить для него итератор tableAndHand.erase (- it), теперь он работает отлично и быстро 🙂

0

Решение

Вы увеличиваете it до трех раз в цикле, прежде чем сравнивать с концом.

Вы стираете, не сохраняя новый итератор.

Множество побочных эффектов.

Заказ if(*it == *(--it)) { не определено, так что вы можете сравнить элемент с самим собой. (== не точка последовательности, так *it а также *(--it) может оцениваться в любом порядке).

Вы не проверяете tableAndHand будучи пустым — вы увеличиваете it перед проверкой.

3

Другие решения

Вы увеличиваете it дважды в каждой итерации цикла:

while(++it != tableAndHand.end()) {  // <---- IN THIS LINE
//HERE IS THE PROBLEM
if(*it == *(--it)) {
++cardCount;
++it;      // <----- AND EITHER HERE
} else {
cardCounts1.insert(pair<int,int>(cardCount,*it));
while(cardCount > 1) {
tableAndHand.erase(--it);
--cardCount;
}
++it;   // <----- OR HERE
}
}

Это означает, что вы запустите за пределы списка раньше, чем вы должны, и сравнение в цикле while:

while (++it != tableAndHand.end())

дает true навсегда, потому что итератор никогда не указывает на конец контейнера именно так.

Это мог работать, если количество элементов четное (хотя, поскольку вы иногда удаляете элементы, это трудно предсказать).


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

1

if(*it == *(--it))

Поведение этого кода не определено: компилятор может оценить --it на правой стороне сравнения, прежде чем он оценивает it на левой стороне, или он может сделать их наоборот.

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

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector