Valgrind在简单的Iterator类中检测到无效的读取错误

时间:2012-01-13 09:18:31

标签: c++ iterator valgrind

Valgrind检测到无效的读取错误我不知道如何修复或更准确:我不知道问题是什么。

Invalid read of size 8
 at 0x443212: std::vector<Tile*, std::allocator<Tile*> >::end() const
 by 0x44296C: Collection<Tile*>::Iterator::operator++()

Iterator类非常简单(实际上是一个有点糟糕的编程),但现在足以满足我的需求。我认为有三种方法可以帮助我找到解决问题的方法:

Iterator(size_t x, size_t y, const TileCollection& tiles)
        : mTiles(&tiles)
        , mX(mTiles->begin())
        , mY(mTiles->at(x).begin())
{   
       std::advance(mX, x); 
       std::advance(mY, y); 

       bool foundFirst = false;

       while (!foundFirst)
       {
              while (mY != mX->end() && *mY == 0) ++mY;

              if (mY != mX->end()) foundFirst = true;
              else
              {
                     ++mX;

                     if (mX != mTiles->end()) mY = mX->begin();
              }
       }
}

Iterator Iterator::operator++()
{
       bool foundNext = false;

       ++mY;

       while (!foundNext)
       {
              while (mY != mX->end() && *mY == 0) ++mY;

              if (mY != mX->end()) foundNext = true;
              else
              {
                     ++mX;

                     if (mX != mTiles->end()) mY = mX->begin();
              }
       }

       return *this;
}

void TileCollection::add(Tile* tile)
{
       Point2D p(tile->getPosition());

       std::vector<Tile*> tmp(1, (Tile*)0);

       if ((size_t)p.x >= mTiles.size())
              mTiles.resize(p.x + 1, tmp);
       if ((size_t)p.y >= mTiles.at(p.x).size())
              mTiles.at(p.x).resize(p.y + 1, (Tile*)0);

       mTiles.at(p.x).at(p.y) = tile;

       ++mNumTiles;
}

导致valgrind错误的实际代码是行:

while (mY != mX->end() && *mY == 0) ++mY;

... Iterator :: operator ++方法。

2 个答案:

答案 0 :(得分:1)

在我看来,至少是operator++

中的以下行
if (mX != mTiles->end()) mY = mX->begin();

缺少合适的else子句。

考虑当mX实际到达mTiles->end()时会发生什么:您将输入外部while循环的新迭代;该循环中的第一行(导致Valgrind错误的行)将评估mX->end(),从而尝试取消引用mX - 但mXmTiles->end(),而不是Iterator更正取消引用集合的结束迭代器,因为它实际上不引用集合的元素。它看起来好像这可能是你的Valgrind错误的原因。

(请注意,构造函数基本上包含相同的代码。)

更一般地说,我认为您需要考虑如何处理到达二维数组的末尾。 operator++的客户端如何检查它是否已到达迭代结束?当你的{{1}}到达二维数组的末尾时,你如何期待它?它应该保护自己不要经常被叫吗?

答案 1 :(得分:0)

您可以尝试拆分语句,以便找出错误发生的位置:

while (mY != mX->end()) // maybe here
{
    if (*mY != 0) // maybe here
    {
        break;
    }
    ++mY; // maybe here
}

使用GCC编译器选项-fno-inline进行编译有助于获得更好的堆栈跟踪,这可以帮助您跟踪错误。它也会使你的程序变得非常慢,所以不要忘记以后删除它。