Как использовать итератор?


Я пытаюсь вычислить расстояние между двумя точками. Две точки я сохранил в векторе в C++: (0,0) и (1,1).

Я должен получить результаты как

0
1.4
1.4
0

но фактический результат, который я получил

0
1
-1
0

Я думаю, что что-то не так с тем, как я использую итератор в векторе. Как я могу исправить эту проблему?

я разместил код ниже.

typedef struct point {
    float x;
    float y;
} point;

float distance(point *p1, point *p2)
{
    return sqrt((p1->x - p2->x)*(p1->x - p2->x) +
                (p1->y - p2->y)*(p1->y - p2->y));
}

int main()
{
    vector <point> po;
    point p1; p1.x = 0; p1.y = 0;
    point p2; p2.x = 1; p2.y = 1;
    po.push_back(p1);
    po.push_back(p2);

    vector <point>::iterator ii;
    vector <point>::iterator jj;
    for (ii = po.begin(); ii != po.end(); ii++)
    {
        for (jj = po.begin(); jj != po.end(); jj++)
        {
            cout << distance(ii,jj) << " ";
        }
    }
    return 0;
}
3 65

3 ответа:

что ваш код компилируется вообще, вероятно, потому, что у вас есть using namespace std куда-то. (В противном случае vector должен быть std::vector.)это то, что я бы не советовал и вы только что представили веские аргументы, почему:
Случайно, ваш звонок поднимает std::distance(), которая принимает два итератора и вычисляет расстояние между ними. Удалите директиву using и префикс всех стандартных типов библиотек с помощью std:: и компилятор скажет вам, что вы пытался передать vector <point>::iterator где a point* не требуется.

чтобы получить указатель на объект, на который указывает итератор, вам нужно разыменовать итератор , который дает ссылку на объект , и взять адрес результата:&*ii.
(Обратите внимание, что указатель будет идеально выполнять все требования для std::vector итератор и некоторые более ранние реализации стандартной библиотеки действительно использовали указатели для этого, что позволило вам лечить std::vector итераторы в качестве указателей. Но современные реализации используют для этого специальный класс итератора. Я полагаю, причина в том, что использование класса позволяет перегружать функции для указателей и итераторов. Кроме того, используя указатели как std::vector итераторы поощряет смешивание указателей и итераторов, что предотвратит компиляцию кода при изменении контейнера.)

но вместо того, чтобы делать это, я предлагаю вам изменить свою функцию так, чтобы она принимала ссылки вместо этого (см. ответ почему это хорошо идея в любом случае.):

float distance(const point& p1, const point& p2)
{
    return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
                (p1.y - p2.y)*(p1.y - p2.y));
}

обратите внимание, что принимаются const ссылки. Это указывает вызывающему объекту, что функция не будет изменять точки, которые она передает.

затем вы можете назвать это так: distance(*ii,*jj).


на боковой ноте, это

typedef struct point {
    float x;
    float y;
} point;

является C-ism ненужным в C++. Просто пиши это

struct point {
    float x;
    float y;
};

это создаст проблемы, если это struct определение когда-либо должно было анализироваться из компилятора C (код должен был бы ссылаться на struct point тогда, а не просто point), но я думаю std::vector и подобное было бы гораздо более сложной задачей для компилятора C в любом случае.

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

cout << distance(&(*ii), &(*jj)) << " ";

Как отметил Sbi: ваша функция расстояния принимает указатели. Было бы лучше переписать вместо этого ссылки на const, что сделало бы функцию более "канонической" c++ и сделало бы синтаксис разыменования итератора менее болезненным.

float distance(const point& i_p1, const point& i_p2)
{
    return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
                (p1.y - p2.y)*(p1.y - p2.y));
}

cout << distance(*ii, *jj) << " ";

вы можете сделать несколько вещей:

  1. сделать distance() функция принимает ссылки на point объекты. Это действительно просто, чтобы сделать вещи более читабельным при вызове :

    float distance(point const& p1, point const& p2)
    {
        return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
                    (p1.y - p2.y)*(p1.y - p2.y));
    }
    
  2. разыменование итераторов при вызове distance()Итак, вы передаете point объекты:

    distance( *ii, *jj)
    

если вы не измените интерфейс distance() функция, возможно, вам придется вызвать его используя что-то вроде следующего, чтобы получить соответствующие указатели:

distance( &*ii, &*jj)