13

我试图在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");

为了获得更多信息,我编写了这个小函数来替换我!=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.

查看反汇编窗口会按预期顺序显示说明。我难住了。可能会发生什么?

4

2 回答 2

12

终于想通了。Microsoft 函数_Debug_message会显示一个对话框,询问您是要中止、重试(调试)还是忽略错误。在显示对话框时,消息泵仍在运行,允许进行其他活动。我的函数再次被调用,这次它运行完成,在此过程中生成大量调试输出。_DEBUG_ERROR如果我在库代码的行上放置一个显式断点,我会捕获错误而无需在后台额外执行。事后回顾一下调试输出,我可以看到预期的错误输出确实在那里,只是埋藏得如此之深,以至于我从未见过它。

于 2013-06-10T16:47:40.380 回答
3

我的直觉告诉我,奥卡姆剃刀是最可能的解释:特别是您在迭代期间使迭代器无效。您在 for 循环中没有 a 的事实++iter进一步强调了它不是对每个元素的直接迭代。

它可能不直接在循环内部,但容器可能在从循环主体调用的调用链中的某个地方有别名——这些错误很容易犯,而且诊断起来绝对残酷。您至少应该在每次迭代时打印容器的大小。

如果您可以访问 Linux 并且有足够小部分的代码重现该问题,您也可以使用 valgrind 来帮助您解决这个问题。

于 2013-06-10T16:24:29.890 回答