Циклы по каждому элементу и разница между оператором стрелка / точка? - PullRequest
0 голосов
/ 15 марта 2019

У меня есть класс Point, в котором есть метод члена для получения позиции:

class Point {
    private:
        int x; int y;
    public:
        Point(int a, int b) {
            x = a; y = b;
        }
        int getX() { return x; }
        int getY() { return y; }
};

Они хранятся в list<Point> с именем listPoints. У меня есть функция, которая проверяет, соответствует ли позиция какой-либо из точек в списке:

bool checkMatch(int x, int y) {
    for (Point p : listPoints) {
        if (p.getX() == x && p.getY() == y) {
            return true;
        }
    }
    return false;
}

Обратите внимание, что . используется для доступа к методам-членам Point, но есть и другой способ:

bool checkMatch(int x, int y) {
    list<Point>::iterator p = listPoints.begin();
    for (; p != listPoints.end(); ++p) {
        if (p->getX() == x && p->getY() == y) {
            return true;
        }
    }
    return false;
}

Чем эта функция отличается от предыдущей, в частности, почему . больше не работает, и мне нужно использовать -> вместо этого для доступа к методам-членам Point? Эти циклы foreach принципиально отличаются?

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Они ничем не отличаются, за некоторыми незначительными исключениями. Во втором цикле вы используете итератор, который является более или менее указателем на сам объект. Это может быть разыменовано, чтобы получить фактический объект.

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

Поскольку вы просто выполняете итерацию по всему диапазону, гораздо понятнее использовать цикл for-ranged. Проще написать и понятнее.

конкретно почему. больше не работает, и мне нужно использовать -> вместо этого для доступа к методам членов Point?

Потому что iterator - это объект, который в основном указывает на реальный объект. Вы не можете переопределить оператор точки, поэтому вместо него operator-> переопределяется для получения объекта. Можно также разыменовать iterator как *p, что позволяет использовать оператор точки (*p).getX()

1 голос
/ 15 марта 2019

Являются ли эти циклы foreach принципиально различными?

Они не отличаются фундаментально.Они немного различаются.

Это аналогично:

int a;
int* ptr = &a;

a = 10;
*ptr = 10;

Последние две строки не являются фундаментально разными.Итератор похож на указатель.Его operator* перегружен, так что использование *p действует так, как будто вы разыменовываете указатель - вы получаете ссылку на элемент в контейнере.

Второй блок кода можно немного изменить нанапоминают первый.

list<Point>::iterator iter = listPoints.begin();
for (; iter != listPoints.end(); ++iter) {
    Point& p = *iter;
    if (p.getX() == x && p.getY() == y) {
        return true;
    }
}

Под крышками первый блок точно такой.

См. документацию о диапазоне- for в стандарте * 1021.* для деталей.

...