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

Я пытаюсь вычислить расстояние между двумя точками. Две точки я сохранил в векторе в 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;
}
71
задан Peter Mortensen 11 October 2015 в 10:54
поделиться

3 ответа

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

Чтобы получить указатель на объект, на который указывает итератор, вам нужно разыменовать итератор, который дает ссылку на объект, и взять адрес результата: & * 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 .Это указывает вызывающей стороне, что функция не изменит передаваемые ей баллы.

Тогда вы можете назвать это так: расстояние (* 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.

190
ответ дан 24 November 2019 в 12:50
поделиться

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

  1. Сделать так, чтобы функция distance () использовала ссылки на точку объекты. Это сделано только для того, чтобы сделать вещи более удобочитаемыми при вызове функции distance () :
     float distance (const point & p1, const point & p2) {{1 }} {
    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) { {1}} 
6
ответ дан 24 November 2019 в 12:50
поделиться

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

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

Как видно из синтаксиса выше, «итератор» во многом похож на обобщенный «указатель». Итератор нельзя использовать напрямую как «свой» объектный тип. На самом деле итераторы настолько похожи на указатели, что многие стандартные алгоритмы, работающие с итераторами, отлично работают и с указателями.

Как заметил Sbi: ваша функция расстояния принимает указатели. Было бы лучше переписать вместо этого использование константных ссылок, что сделало бы функцию более «канонической» 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) << " ";
21
ответ дан 24 November 2019 в 12:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: