Очень странное поведение обратного итератора в C++
Это из теста, который я сегодня провел на своем компьютере, меня попросили реализовать класс Гарднера с двумя функциями - каждая из них пометит участок земли, на котором стоит Гарднер, как скашенный, и переместит Гарднера на 3 единицы влево или вправо, Если на пути Гарднера есть какой-либо участок земли, помеченный как скошенный, он пропустит его и перейдет к следующему.
Я смоделировал землю, используя вектор логических переменных. Я использовал std::find() с прямым итератором, чтобы найти землю, которая не косится в правильном направлении, и я использовал обратный итератор в левом направлении. Прямой итератор работает как положено. Однако обратный итератор дал странные результаты. Если быть более точным, например, в отладчике Visual Studio, он показал значение, на которое указывает обратный итератор, значение false(что и ожидалось), но когда я разыменовал обратный итератор, я получил значение true. Это может быть воспроизведено в следующем коде, я приложил код, любая помощь приветствуется.
#include <iostream>
#include <vector>
#include <algorithm>
class Gardener
{
public:
Gardener(int n, int position)
: mLands(n, false)
, mPosition(position - 1)
{
}
/**
* \brief Gardener has mowed the lawn at current house and moved left.
*
**/
void mowAndMoveLeft()
{
mLands[mPosition] = true;
//auto it = std::find(mHouses.rbegin() + mHouses.size() - mPosition + 1, mHouses.rend(), false);
//it = std::find(it + 1, mHouses.rend(), false);
//it = std::find(it + 1, mHouses.rend(), false);
auto it = mLands.rbegin() + mLands.size() - mPosition + 1;
int counter = 3;
while (--counter >= 0)
{
while (it != mLands.rend())
{
if (*it == false)
{
++it;
break;
}
++it;
}
}
mPosition = mLands.rend() - it;
}
/**
* \brief Gardener has mowed the lawn at current house and moved right.
*
**/
void mowAndMoveRight()
{
mLands[mPosition] = true;
auto it = std::find(mLands.begin() + mPosition + 1, mLands.end(), false);
it = std::find(it + 1, mLands.end(), false);
it = std::find(it + 1, mLands.end(), false);
mPosition = it - mLands.begin();
}
/**
* \return house number that gardener is mowing right now.
*
**/
int whereAmI()
{
return mPosition + 1;
}
private:
std::vector<bool> mLands;
std::size_t mPosition;
};
#ifndef RunTests
int main(int argc, const char* argv[])
{
Gardener g(10, 2);
std::cout << g.whereAmI() << '\n';
g.mowAndMoveRight();
std::cout << g.whereAmI() << '\n';
g.mowAndMoveRight();
std::cout << g.whereAmI() << '\n';
g.mowAndMoveLeft();
std::cout << g.whereAmI() << '\n';
}
#endif
1 ответ
Чтобы понять, что происходит с вашим обратным итератором, посмотрите на reverse_iterator в cppreference. Более конкретно, посмотрите на метод base():
Базовый итератор ссылается на следующий элемент (из
std::reverse_iterator::iterator_type
в перспективе) к элементуreverse_iterator
в настоящее время указывает на. То есть&*(rit.base() - 1) == &*rit
,
По-английски:
*rit.base()
(обратного итератора) будет обращаться к элементу mLands, который является одним до того, что *rit
иметь доступ. Этот сдвиг между *rit
а также *rit.base()
позволяет сделать mLands.rend()
логически указывает на первый элемент mLands
, Это зеркальный эквивалент mLands.end()
указывая на последний элемент mLands
,
Теперь о том, что вы видите в отладчике. Скорее всего, ваш отладчик показывает вам значение rit.base()
который указывает на один элемент ранее mLands
, тогда что rit
указывает логически. Это может объяснить несоответствие, которое вы видите здесь. Для отладки, если вы не уверены, что показывает отладчик, самое безопасное - напечатать значение *rit
или сохранить его во временной переменной и проверить это в отладчике.