Как использовать итератор?
Я пытаюсь вычислить расстояние между двумя точками. Две точки я сохранил в векторе в 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 ответа:
что ваш код компилируется вообще, вероятно, потому, что у вас есть
using namespace std
куда-то. (В противном случаеvector
должен бытьstd::vector
.)это то, что я бы не советовал и вы только что представили веские аргументы, почему:
Случайно, ваш звонок поднимаетstd::distance()
, которая принимает два итератора и вычисляет расстояние между ними. Удалите директиву using и префикс всех стандартных типов библиотек с помощьюstd::
и компилятор скажет вам, что вы пытался передатьvector <point>::iterator
где apoint*
не требуется.чтобы получить указатель на объект, на который указывает итератор, вам нужно разыменовать итератор , который дает ссылку на объект , и взять адрес результата:
&*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) << " ";
вы можете сделать несколько вещей:
сделать
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)); }
разыменование итераторов при вызове
distance()
Итак, вы передаетеpoint
объекты:distance( *ii, *jj)
если вы не измените интерфейс
distance()
функция, возможно, вам придется вызвать его используя что-то вроде следующего, чтобы получить соответствующие указатели:distance( &*ii, &*jj)