Невозможная последовательность событий
Я пытаюсь найти загадочную проблему итератора в цикле for
. Я получаю сообщение об ошибке в итераторе operator!=
, что обычно означает, что сравниваемые итераторы не принадлежат одному и тому же контейнеру. Прослеживая реализацию Microsoft в библиотеке, operator!=
вызывает operator==
, где этот тест верен:
bool operator==(const _Myiter& _Right) const
{ // test for iterator equality
#if _ITERATOR_DEBUG_LEVEL == 2
if (this->_Getcont() == 0
|| this->_Getcont() != _Right._Getcont())
{ // report error
_DEBUG_ERROR("list iterators incompatible");
В попытке получить дополнительную информацию я написал эту небольшую функцию для замены my !=
в цикле for
:
template<typename iter>
bool bang_equal(const iter & left, const iter & right)
{
static int count = 0;
auto p1 = left._Getcont();
auto p2 = right._Getcont();
ATLTRACE("Iterator comparison left _Getcont()=%p right _Getcont()=%p %d\n", p1, p2, ++count);
MemoryBarrier();
bool b = left != right;
MemoryBarrier();
auto p3 = left._Getcont();
auto p4 = right._Getcont();
ATLTRACE(" left _Getcont()=%p right _Getcont()=%p %d\n", p3, p4, ++count);
return b;
}
Здесь, где это становится интересным. Я все еще получаю ошибку в выражении left != right
, и отладчик останавливается там, но либо первый ATLTRACE
был пропущен, либо второй запустился раньше времени! Выход отладчика имеет обе строки, а значение count
, как показано отладчиком, соответствует последней строке вывода.
Iterator comparison left _Getcont()=07D0B2C8 right _Getcont()=07D0B2C8 2984
left _Getcont()=07D0B2C8 right _Getcont()=07D0B2C8 2985
Myprog.exe has triggered a breakpoint.
В окне разборки отображаются инструкции в ожидаемом порядке. Я в тупике. Что может произойти?
Ответы
Ответ 1
Наконец понял это. Функция Microsoft _Debug_message
отображает диалоговое окно с вопросом, хотите ли вы прервать, повторить попытку (debug) или проигнорировать ошибку. Пока отображается диалоговое окно, насос сообщений все еще работает, что позволяет выполнять другие действия. Моя функция была вызвана снова, и на этот раз она завершилась, создавая в ней много отладочной информации. Если я поставлю явную точку останова в строке _DEBUG_ERROR
в коде библиотеки, я поймаю ошибку без дополнительного выполнения в фоновом режиме. Оглядываясь назад на вывод отладки с учетом ретроспективного анализа, я вижу, что ожидаемый вывод ошибки действительно был там, только что похоронен до сих пор, что я его никогда не видел.
Ответ 2
Моя интуиция подсказывает мне, что бритва Оккама является наиболее вероятным объяснением здесь: В частности, что вы инертность итератора недействительны. Тот факт, что в цикле for отсутствует ++iter
, еще раз подчеркивает, что он не является прямой итерацией по каждому элементу.
Вероятно, он не находится непосредственно внутри цикла, но контейнер, вероятно, сглажен где-то внутри вызывающей цепочки, вызываемой из тела цикла - это довольно простые ошибки, чтобы сделать и абсолютно жестоко диагностировать. Вы должны хотя бы напечатать размер контейнера на каждой итерации.
Если у вас есть доступ к Linux и достаточно небольшая часть кода, который воспроизводит проблему, вы можете использовать valgrind, чтобы помочь вам также выследить это.