Dlaczego warto używać iteratorów zamiast indeksów tablicy?

Weź następujące dwie linijki kodu:

for (int i = 0; i < some_vector.size(); i++)
{
    //do stuff
}

I to:

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
    some_iterator++)
{
    //do stuff
}
Powiedziano mi, że preferowany jest drugi sposób. Dlaczego tak jest?
Author: Jason Baker, 2008-09-25

25 answers

Pierwsza forma jest efektywna tylko wtedy, gdy wektor.rozmiar() to szybka operacja. Dotyczy to na przykład wektorów, ale nie List. Ponadto, co planujesz zrobić w ciele pętli? Jeśli planujesz uzyskać dostęp do elementów jak w

T elem = some_vector[i];

Następnie zakładamy, że kontener ma zdefiniowaną operator[](std::size_t). Ponownie, jest to prawdą dla vector, ale nie dla innych kontenerów.

Użycie iteratorów przybliża użytkownika do niezależności kontenerów. Nie robisz założenia dotyczące możliwości dostępu losowego lub szybkiej operacji size(), tyle że kontener ma możliwości iteratora.

Możesz ulepszyć swój kod używając standardowych algorytmów. W zależności od tego, co próbujesz osiągnąć, możesz zdecydować się na użycie std::for_each(), std::transform() i tak dalej. Używając standardowego algorytmu, a nie jawnej pętli, unikasz ponownego wynalezienia koła. Twój kod będzie prawdopodobnie bardziej wydajny (biorąc pod uwagę wybrany algorytm), poprawny i wielokrotnego użytku.

 186
Author: wilhelmtell,
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
2011-05-31 15:13:07

Ponieważ nie przywiązujesz kodu do konkretnej implementacji listy some_vector. jeśli używasz indeksów tablicowych, musi to być jakaś forma tablicy; jeśli używasz iteratorów, możesz użyć tego kodu w dowolnej implementacji listy.

 49
Author: cruizer,
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
2008-09-25 03:02:54

Jest częścią nowoczesnego procesu indoktrynacji C++. Iteratory są jedynym sposobem na iterację większości kontenerów, więc używasz go nawet z wektorami, aby dostać się do właściwego sposobu myślenia. Poważnie, to jedyny powód, dla którego to robię - chyba nigdy nie zamieniłem wektora na inny rodzaj kontenera.


Wow, po trzech tygodniach to nadal jest przegłosowane. Myślę, że nie opłaca się być trochę języczkiem w policzku.

Myślę, że indeks tablicy jest bardziej czytelny. Pasuje składnia używana w innych językach oraz składnia używana w staromodnych tablicach C. Jest też mniej gadatliwy. Wydajność powinna być wyprana, jeśli twój kompilator jest dobry, i nie ma prawie żadnych przypadków, w których i tak ma to znaczenie.

Mimo to wciąż często używam iteratorów z wektorami. Uważam, że iterator jest ważną koncepcją, więc promuję go, kiedy tylko mogę.

 45
Author: Mark Ransom,
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
2008-10-21 22:19:55

Imagine some_vector jest zaimplementowany z linked-list. Następnie żądanie elementu w i-tym miejscu wymaga operacji i, aby przejść listę węzłów. Teraz, jeśli używasz iteratora, ogólnie rzecz biorąc, dołoży on wszelkich starań, aby był jak najbardziej efektywny (w przypadku listy połączonej, utrzyma wskaźnik do bieżącego węzła i awansuje go w każdej iteracji, wymagając tylko jednej operacji).

Więc daje dwie rzeczy:

  • abstrakcja użycia: po prostu chcesz iterować niektóre elementy, nie dbasz o to, jak to zrobić
  • Wydajność
 32
Author: asterite,
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
2008-09-25 11:57:56

Będę tutaj orędownikiem diabłów, a nie polecam iteratorów. Głównym powodem tego jest cały kod źródłowy, nad którym pracowałem od tworzenia aplikacji desktopowych do tworzenia gier, ani nie musiałem używać iteratorów. Cały czas nie były one wymagane, a po drugie ukryte założenia, bałagan w kodzie i koszmary debugowania, które dostajesz z iteratorami, sprawiają, że są doskonałym przykładem, aby nie używać ich w żadnych aplikacjach wymagających szybkości.

Even from a maintence stand pokaż, że są w rozsypce. To nie z ich powodu, ale z powodu wszystkich aliasingu, które dzieją się za sceną. Skąd mam wiedzieć, że nie zaimplementowałeś własnej wirtualnej listy wektorów lub tablic, która robi coś zupełnie innego niż standardy. Czy wiem, jaki typ jest obecnie w czasie wykonywania? Przeciążyłeś operatora, nie miałem czasu sprawdzić całego kodu źródłowego. Cholera, czy ja w ogóle wiem, jakiej wersji STL używasz?

Następny problem z iteratorami jest nieszczelny abstrakcji, choć istnieje wiele stron internetowych, które omawiają to szczegółowo z nimi.

Przepraszam, nie widziałem i nadal nie widziałem żadnego punktu w iteratorach. Jeśli abstrakcyjny listę lub wektor z dala od Ciebie, podczas gdy w rzeczywistości powinieneś już wiedzieć, co wektor lub Lista do czynienia z jeśli nie to po prostu będzie ustawianie się na kilka świetnych sesji debugowania w przyszłości.

 25
Author: Chad,
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
2008-09-25 04:53:04

Możesz użyć iteratora, jeśli zamierzasz dodawać / usuwać elementy do wektora podczas iteracji nad nim.

some_iterator = some_vector.begin(); 
while (some_iterator != some_vector.end())
{
    if (/* some condition */)
    {
        some_iterator = some_vector.erase(some_iterator);
        // some_iterator now positioned at the element after the deleted element
    }
    else
    {
        if (/* some other condition */)
        {
            some_iterator = some_vector.insert(some_iterator, some_new_value);
            // some_iterator now positioned at new element
        }
        ++some_iterator;
    }
}

Jeśli używasz indeksów, musisz przetasować elementy w górę/w dół tablicy, aby obsłużyć wstawianie i usuwanie.

 19
Author: Brian Matthews,
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-05-21 08:56:17

Rozdzielenie obaw

Bardzo miło jest oddzielić kod iteracji od' rdzenia ' pętli. To prawie decyzja projektowa.

Rzeczywiście, iteracja przez indeks wiąże cię z implementacją kontenera. Poproszenie kontenera o iterator początku i końca, umożliwia użycie kodu pętli z innymi typami kontenerów.

Również, w std::for_each sposób, powiedzieć kolekcji, co zrobić, zamiast zapytać coś o jego wewnętrzne

Standard 0x wprowadzi zamknięcia, które sprawią, że to podejście będzie znacznie łatwiejsze w użyciu - przyjrzyj się potędze ekspresyjnej np. [1..6].each { |i| print i; } Rubiego...

Wydajność

Ale być może dużo nadzorowanym problemem jest to, że użycie podejścia for_each daje możliwość równoległej iteracji - Intel threading blocks może rozłożyć blok kodu na liczbę procesorów w systemie!

Uwaga: po odkryciu algorithms biblioteka, a szczególnie foreach, przeszedłem przez dwa lub trzy miesiące pisania śmiesznie małych' pomocniczych ' struktur operatorskich, które doprowadzą twoich kolegów programistów do szaleństwa. Po tym czasie wróciłem do pragmatycznego podejścia - małe ciała pętelkowe nie zasługują już na foreach:)

Obowiązkowym odniesieniem do iteratorów jest książka"Extended STL".

GoF ma mały akapit na końcu wzorca iteratora, który mówi o tej marce iteracji; to nazywany "iteratorem wewnętrznym". Zobacz też tutaj .

 16
Author: xtofl,
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
2014-11-19 06:42:18

Ponieważ jest bardziej obiektowy. w przypadku iteracji z indeksem Zakładamy:

A) że obiekty te są uporządkowane
b) że obiekty te można uzyskać za pomocą indeksu
c) że przyrost indeksu uderzy w każdy element
d) że indeks zaczyna się od zera

W przypadku iteratora mówisz "daj mi wszystko, żebym mógł z nim pracować", nie wiedząc, jaka jest podstawowa implementacja. (W Javie istnieją kolekcje, do których nie można uzyskać dostępu poprzez index)

Ponadto, z iteratorem, nie trzeba się martwić o wyjście poza granice tablicy.

 14
Author: cynicalman,
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
2008-09-25 03:04:54

Kolejną miłą rzeczą w iteratorach jest to, że lepiej pozwalają Ci wyrazić (i wyegzekwować) Twoje const-preferencje. Ten przykład zapewnia, że nie zmienisz wektora w środku pętli:


for(std::vector<Foo>::const_iterator pos=foos.begin(); pos != foos.end(); ++pos)
{
    // Foo & foo = *pos; // this won't compile
    const Foo & foo = *pos; // this will compile
}
 14
Author: Pat Notz,
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
2008-09-25 03:24:32

Poza wszystkimi innymi doskonałymi odpowiedziami... int może nie być wystarczająco duży dla Twojego wektora. Zamiast tego, jeśli chcesz użyć indeksowania, użyj size_type dla kontenera:

for (std::vector<Foo>::size_type i = 0; i < myvector.size(); ++i)
{
    Foo& this_foo = myvector[i];
    // Do stuff with this_foo
}
 12
Author: Pat Notz,
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-11 10:26:48

Prawdopodobnie powinienem zwrócić uwagę, że możesz również zadzwonić

std::for_each(some_vector.begin(), some_vector.end(), &do_stuff);

 11
Author: MSalters,
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
2008-09-26 12:10:00

Iteratory STL są tam głównie po to, aby algorytmy STL, takie jak sort, mogły być niezależne od kontenera.

Jeśli chcesz tylko zapętlić wszystkie wpisy w wektorze, użyj stylu pętli index.

Jest mniej pisanie i łatwiejsze do analizy dla większości ludzi. Byłoby miło, gdyby C++ miał prostą pętlę foreach bez przesadzania z magią szablonów.

for( size_t i = 0; i < some_vector.size(); ++i )
{
   T& rT = some_vector[i];
   // now do something with rT
}
'
 6
Author: Jeroen Dirks,
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
2008-09-25 13:46:04

Myślę, że to nie robi wielkiej różnicy dla wektora. Wolę używać indeksu, ponieważ uważam go za bardziej czytelny i możesz zrobić losowy dostęp, jak skakanie do przodu 6 przedmiotów lub skakanie do tyłu, jeśli zajdzie taka potrzeba.

Lubię również nawiązywać do elementu wewnątrz pętli tak, aby nie było zbyt wiele nawiasów kwadratowych wokół miejsca:

for(size_t i = 0; i < myvector.size(); i++)
{
    MyClass &item = myvector[i];

    // Do stuff to "item".
}

Użycie iteratora może być dobre, jeśli uważasz, że możesz potrzebować zastąpić wektor listą w pewnym momencie w przyszłość i wygląda bardziej stylowo dla maniaków STL, ale nie mogę wymyślić żadnego innego powodu.

 5
Author: Adam Pierce,
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
2008-09-25 03:03:05

Druga forma dokładniej przedstawia to, co robisz. W twoim przykładzie nie zależy ci na wartości i, naprawdę - wszystko, co chcesz, to następny element w iteratorze.

 3
Author: Colen,
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
2008-09-25 03:20:39

Po tym, jak dowiedziałem się trochę więcej na temat tej odpowiedzi, zdałem sobie sprawę, że było to trochę uproszczone. Różnica między tą pętlą:

for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
    some_iterator++)
{
    //do stuff
}

I ta pętla:

for (int i = 0; i < some_vector.size(); i++)
{
    //do stuff
}

Jest dość minimalne. W rzeczywistości, składnia robienia pętli w ten sposób wydaje się na mnie wzrastać:

while (it != end){
    //do stuff
    ++it;
}

Iteratory odblokowują dość potężne funkcje deklaratywne, a w połączeniu z biblioteką algorytmów STL można zrobić całkiem fajne rzeczy, które wykraczają poza zakres array index administrativia.

 3
Author: Jason Baker,
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
2008-12-16 22:46:17

Indeksowanie wymaga dodatkowej operacji mul. Na przykład dla vector<int> v kompilator konwertuje v[i] na &v + sizeof(int) * i.

 3
Author: Marc Eaddy,
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
2018-08-21 01:07:18

Podczas iteracji nie musisz znać liczby elementów do przetworzenia. Po prostu potrzebujesz elementu, a Iteratory robią takie rzeczy bardzo dobrze.

 2
Author: Sergey Stolyarov,
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
2008-09-25 04:25:11

Już kilka dobrych punktów. Mam kilka dodatkowych komentarzy:

  1. Zakładając, że mówimy o bibliotece standardowej C++, "vector" oznacza kontener dostępu losowego, który ma Gwarancje C-array (dostęp losowy, układ pamięci contiguos itp.). Gdybyś powiedział "some_container", wiele z powyższych odpowiedzi byłoby dokładniejszych(niezależność kontenerów itp.).

  2. Aby wyeliminować wszelkie zależności od optymalizacji kompilatora, można przenieść some_vector.size () poza pętlą w zindeksowanym kodzie, w ten sposób:

    const size_t numElems = some_vector.size();
    for (size_t i = 0; i 
  3. Zawsze Iteratory pre-increment i traktuj post-increment jako wyjątkowe przypadki.

for (some_iterator = some_vector.begin (); some_iterator != some_vector.end (); ++some_iterator) {//do stuff }

Więc zakładając i indeksowalny std::vector<> jak kontener, nie ma powodu, aby preferować jeden nad drugim, kolejno przechodząc przez kontener. Jeśli musisz odnosić się do starszego lub nowszego elementu indeksuje często, wtedy wersja zindeksowana jest bardziej odpowiednia.

Ogólnie rzecz biorąc, korzystanie z iteratorów jest preferowane, ponieważ algorytmy z nich korzystają, a zachowanie można kontrolować (i pośrednio udokumentować) poprzez zmianę typu iteratora. Zamiast iteratorów można użyć lokalizacji tablicy, ale różnica w składni będzie widoczna.

 1
Author: user22044,
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
2008-09-25 08:30:47

Nie używam iteratorów z tego samego powodu, dla którego nie lubię foreach-statements. Mając wiele pętli wewnętrznych, trudno jest śledzić zmienne globalne / członkowskie bez konieczności zapamiętywania wszystkich lokalnych wartości i nazw iteratorów. Przydatne jest użycie dwóch zestawów indeksów na różne okazje:

for(int i=0;i<anims.size();i++)
  for(int j=0;j<bones.size();j++)
  {
     int animIndex = i;
     int boneIndex = j;


     // in relatively short code I use indices i and j
     ... animation_matrices[i][j] ...

     // in long and complicated code I use indices animIndex and boneIndex
     ... animation_matrices[animIndex][boneIndex] ...


  }

Nie chcę nawet skracać rzeczy takich jak " animation_matrices[i]" do jakiegoś przypadkowego "anim_matrix" - named-iterator na przykład, ponieważ wtedy nie widać wyraźnie z której tablicy pochodzi ta wartość.

 1
Author: AareP,
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
2009-07-14 23:14:25

Nawet lepsze niż "mówienie procesorowi, co ma robić" (imperatywne) jest "mówienie bibliotekom, czego chcesz" (funkcjonalne).

Więc zamiast używać pętli powinieneś nauczyć się algorytmów obecnych w stl.

 0
Author: Leonardo Constantino,
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
2008-09-25 04:58:46

Dla niezależności kontenera

 0
Author: all2one,
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
2008-09-25 11:16:14

Zawsze używam array index, ponieważ wiele moich aplikacji wymaga czegoś w rodzaju "wyświetl miniaturkę obrazu". Więc napisałem coś takiego:

some_vector[0].left=0;
some_vector[0].top =0;<br>

for (int i = 1; i < some_vector.size(); i++)
{

    some_vector[i].left = some_vector[i-1].width +  some_vector[i-1].left;
    if(i % 6 ==0)
    {
        some_vector[i].top = some_vector[i].top.height + some_vector[i].top;
        some_vector[i].left = 0;
    }

}
 0
Author: Krirk,
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
2012-04-30 11:02:51

Obie implementacje są poprawne, ale wolałbym pętlę 'for'. Ponieważ zdecydowaliśmy się na użycie wektora, a nie innego kontenera, użycie indeksów byłoby najlepszą opcją. Używanie iteratorów z wektorami straciłoby tę samą korzyść z posiadania obiektów w ciągłych blokach pamięci, które ułatwiają dostęp do nich.

 0
Author: Messiah,
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
2012-07-02 11:04:57
  • Jeśli lubisz być blisko metalu / nie ufasz ich szczegółom implementacji, nie używaj iteratorów .
  • Jeśli podczas tworzenia regularnie zmieniasz jeden typ kolekcji na inny, używaj iteratorów .
  • jeśli trudno Ci zapamiętać, jak iteraować różne rodzaje zbiorów (być może masz kilka typów z kilku różnych źródeł zewnętrznych w użyciu), Użyj iteratorów, aby ujednolicić środki, za pomocą których poruszasz się po elementach. To dotyczy np. zamiany listy połączonej z listą tablic.
Naprawdę, to wszystko. To nie jest tak, że masz zamiar uzyskać więcej zwięzłości w obu kierunkach średnio, a jeśli zwięzłość naprawdę jest twoim celem, zawsze można wycofać się na makra.
 0
Author: Arcane Engineer,
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-11-15 12:58:07

Nikt jeszcze nie wspomniał, że jedną z zalet indeksów jest to, że nie stają się one nieważne, gdy dodajesz je do sąsiedniego kontenera, takiego jak std::vector, dzięki czemu możesz dodawać elementy do kontenera podczas iteracji.

Jest to również możliwe z iteratorami, ale musisz wywołać reserve(), a zatem musisz wiedzieć, ile elementów dodasz.

 0
Author: danpla,
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-09-11 17:32:20