Подтвердить что ты не робот

Невозможная последовательность событий

Я пытаюсь найти загадочную проблему итератора в цикле 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.

В окне разборки отображаются инструкции в ожидаемом порядке. Я в тупике. Что может произойти?

4b9b3361

Ответ 1

Наконец понял это. Функция Microsoft _Debug_message отображает диалоговое окно с вопросом, хотите ли вы прервать, повторить попытку (debug) или проигнорировать ошибку. Пока отображается диалоговое окно, насос сообщений все еще работает, что позволяет выполнять другие действия. Моя функция была вызвана снова, и на этот раз она завершилась, создавая в ней много отладочной информации. Если я поставлю явную точку останова в строке _DEBUG_ERROR в коде библиотеки, я поймаю ошибку без дополнительного выполнения в фоновом режиме. Оглядываясь назад на вывод отладки с учетом ретроспективного анализа, я вижу, что ожидаемый вывод ошибки действительно был там, только что похоронен до сих пор, что я его никогда не видел.

Ответ 2

Моя интуиция подсказывает мне, что бритва Оккама является наиболее вероятным объяснением здесь: В частности, что вы инертность итератора недействительны. Тот факт, что в цикле for отсутствует ++iter, еще раз подчеркивает, что он не является прямой итерацией по каждому элементу.

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

Если у вас есть доступ к Linux и достаточно небольшая часть кода, который воспроизводит проблему, вы можете использовать valgrind, чтобы помочь вам также выследить это.