Я хочу распечатать все дубликаты из мультимножества, но почему-то итераторы ведут себя странно для меня. Как можно исправить этот код? Этот код приводит к вечному циклу, который меня удивляет.
#include <set>
#include <iostream>
#include <sstream>
static void print_duplicate(const std::multiset<int>& mset)
{
std::stringstream error_msg;
for (auto it = mset.begin(); it != mset.end(); ++it)
{
unsigned count = mset.count(*it);
if (count < 2)
continue;
error_msg << "Duplicated numbers found:\n";
for (unsigned i = 0; i < count; ++it, ++i)
error_msg << "\tNum:" << *it << "\n";
}
std::cout << error_msg.str();
}
int main()
{
std::multiset<int> mset;
// fill it
mset.insert(1);
mset.insert(1);
mset.insert(1);
print_duplicate(mset);
}
РЕДАКТИРОВАТЬ
Я добавил — это в конце цикла
for (unsigned i = 0; i < count; ++it, ++i)
error_msg << "\tNum:" << *it << "\n";
--it; // this line fix it
}
for (unsigned i = 0; i < count; ++it, ++i)
Когда этот цикл заканчивается, it
будет равен mset.end()
и так как у вас еще есть другой ++it
из основного цикла, вы получаете что-то другое mset.end()
следовательно, программа никогда не заканчивается.
Внутри вашего внешнего цикла вы можете увеличить it
больше чем единожды. Таким образом, условие it != mset.end()
никогда не может быть правдой, потому что конец уже пропущен. Инкрементирование итератора «за конец» является неопределенным поведением, что означает, что он также может молча завершаться сбоем.
Возможное решение может быть также проверить it != mset.end()
во внутреннем for
-loop:
for (unsigned i = 0; (i < count) && (it != mset.end()); ++it, ++i)
error_msg << "\tNum:" << *it << "\n";
Кажется, проблема в том, что вы проскользнули через конец, не обнаружив его. в mset
вы создаете, есть только 1
s. Это означает count
будет 3 и вложенный for
(тот, над i
) выполнит 3 раза; когда это закончится, it
будет равен mset.end()
, Тогда контроль достигает конца внешнего for
а также it
увеличивается, становится незаконным и, что более важно, отличается от mset.end()
, Это означает, что внешний цикл никогда не заканчивается.
Быстрое исправление: добавьте дополнительную строку после внутреннего цикла: it—;
Причина объясняется в ответе Angew.
Измените цикл for на этот:
for(std::container::iterator it=mset.begin(), it_next=it; it!=mset.end(); it=it_next) {
++it_next;
...
}
По сути, вы пропускаете конец цикла, потому что вы проверяете переменную в своем итераторе. Инкремент только вторичного итератора предотвратит это.