Valgrind обнаруживает неверную ошибку чтения в простом классе Iterator - PullRequest
0 голосов
/ 13 января 2012

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 ]

1 голос
/ 13 января 2012

Мне кажется, что, по крайней мере, следующая строка в operator++

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

отсутствует подходящее условие else.

Рассмотрим, что происходит, когда mX фактически достигает mTiles->end(): вы введете новую итерацию внешнего цикла while; первая строка в этом цикле (строка, которая вызывает ошибку Valgrind) будет оценивать mX->end() и, таким образом, будет пытаться разыменовать mX, но mX будет mTiles->end(), и некорректно разыменовывать конечный итератор коллекция, поскольку она на самом деле не ссылается на элемент коллекции. Мне кажется, что это может быть причиной вашей ошибки в Valgrind.

(Обратите внимание, что конструктор содержит, по сути, один и тот же код.)

В целом, я думаю, вам нужно подумать о том, как вы справляетесь с достижением конца вашего двумерного массива. Как клиент вашего Iterator проверяет, достиг ли он конца итерации? Как вы ожидаете, что ваш operator++ справится со случаем, когда он достигнет конца двумерного массива? Должен ли он защитить себя от слишком частого вызова?

0 голосов
/ 13 января 2012

Вы можете попытаться разделить оператор, чтобы узнать, где происходит ошибка:

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

Компиляция с опцией компилятора GCC -fno-inline помогает получить более качественную трассировку стека, которая может помочьвам отследить ошибку.Это также сделает вашу программу очень медленной, поэтому не забудьте удалить ее позже.

...