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;
}
Author: Peter Mortensen, 2010-04-26

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.

 167
Author: sbi,
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) << " ";
 18
Author: Joris Timmermans,
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:

  1. Spraw, aby Funkcja distance() przyjmowała odwołania do obiektów point. Jest to tak naprawdę tylko po to, aby rzeczy były bardziej czytelne podczas wywoływania funkcji distance():

    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. Dereferencja iteratorów podczas wywoływania distance() więc mijasz point 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)
 6
Author: Michael Burr,
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