Jak korzystać z iteratora?
Próbuję obliczyć odległość między dwoma punktami. Dwa punkty zapisałem w wektorze w C++: (0,0) i (1,1).
I ' m supposed to get results as
0
1.4
1.4
0
Ale faktyczny wynik jaki otrzymałem to
0
1
-1
0
Myślę, że coś jest nie tak ze sposobem w jaki używam iteratora w vector.
Jak mogę rozwiązać ten problem?
Zamieściłem poniższy kod.
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 answers
To, że Twój kod w ogóle kompiluje, prawdopodobnie dlatego, że masz gdzieś using namespace std
. (Inaczej vector
musiałoby być std::vector
.) odradzam a Ty właśnie podałeś dobry przypadek dlaczego:
Przez przypadek Twoje połączenie odbiera std::distance()
, które bierze dwa Iteratory i oblicza odległość między nimi. Usuń dyrektywę using i przedrostek wszystkie standardowe typy bibliotek za pomocą std::
, a kompilator powie Ci, że próbowałeś przekazać vector <point>::iterator
, gdzie point*
było wymagane.
Aby uzyskać wskaźnik do obiektu, do którego wskazuje iterator, musisz odwołać się do iteratora-który daje odniesienie do obiektu - i przyjąć adres wyniku: &*ii
.
(Zauważ, że wskaźnik idealnie spełniałby wszystkie wymagania dla iteratora std::vector
, a niektóre wcześniejsze implementacje biblioteki standardowej rzeczywiście używały do tego wskaźników, co pozwalało traktować iteratory std::vector
jako wskaźniki. Ale współczesne implementacje używają specjalnego iteratora Klasa za to. Przypuszczam, że powodem jest to, że użycie klasy pozwala na przeciążenie funkcji wskaźników i iteratorów. Ponadto używanie wskaźników jako iteratorów std::vector
zachęca do mieszania wskaźników i iteratorów, co uniemożliwi kompilację kodu po zmianie kontenera.)
Ale zamiast tego, sugeruję zmienić swoją funkcję tak, aby zamiast tego przyjmowała odwołania (zobacz ta odpowiedź dlaczego to i tak dobry pomysł.) :
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));
}
Zauważ, że punkty są taken by const
references. Oznacza to dla wywołującego, że funkcja nie zmieni przekazywanych punktów.
Wtedy możesz to nazwać tak: distance(*ii,*jj)
.
Na marginesie, to
typedef struct point {
float x;
float y;
} point;
Jest C-ism niepotrzebnym w C++. Po prostu przeliteruj
struct point {
float x;
float y;
};
To by sprawiało problemy, gdyby ta definicja struct
kiedykolwiek była analizowana z kompilatora C (kod musiałby odnosić się do struct point
, a nie po prostu point
), ale myślę, że std::vector
i podobne byłoby o wiele bardziej w każdym razie wyzwanie dla kompilatora C.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:33
Przypadkiem używasz wbudowanej funkcji STL "distance", która oblicza odległość między iteratorami, zamiast wywoływać własną funkcję distance. Musisz "dereferować" swoje Iteratory, aby uzyskać zawarty obiekt.
cout << distance(&(*ii), &(*jj)) << " ";
Jak widać z powyższej składni, "iterator "jest dość podobny do uogólnionego"wskaźnika". Iterator nie może być używany bezpośrednio jako obiekt typu "Twój". W rzeczywistości Iteratory są tak podobne do wskaźników, że wiele standardowych algorytmy działające na iteratorach działają również dobrze na wskaźnikach.
Jak zauważył Sbi: twoja funkcja odległości przyjmuje wskaźniki. Lepiej byłoby ją przepisać jako odwołanie do const, co uczyniłoby funkcję bardziej "kanoniczną" w c++, a składnię dereferencji iteratora mniej bolesną.
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) << " ";
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-12 19:15:33
Możesz zrobić kilka rzeczy:
-
Spraw, aby Funkcja
distance()
przyjmowała odwołania do obiektówpoint
. Jest to tak naprawdę tylko po to, aby rzeczy były bardziej czytelne podczas wywoływania funkcjidistance()
: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)); }
-
Dereferencja iteratorów podczas wywoływania
distance()
więc mijaszpoint
obiekty:distance( *ii, *jj)
Jeśli nie zmienisz interfejsu funkcji distance()
, być może będziesz musiał wywołać ją za pomocą czegoś takiego jak poniżej, aby uzyskać odpowiednie wskaźniki:
distance( &*ii, &*jj)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-11 10:55:56