Jestem nowy w języku C ++. Zacząłem używać wektorów i zauważyłem, że w całym kodzie, który widzę, aby iterować przez wektor za pomocą indeksów, pierwszy parametr for
pętli jest zawsze oparty na wektorze. W Javie mógłbym zrobić coś takiego z ArrayList:
for(int i=0; i < vector.size(); i++){
vector[i].doSomething();
}
Czy jest jakiś powód, dla którego nie widzę tego w C ++? Czy to zła praktyka?
c++
coding-style
for-loop
iterator
Flynn
źródło
źródło
std::vector<int>::size_type i = 0;
, czy możestd::vector<int>::iterator it = vector.begin();
?std::vector
: Jaka jest najlepsza / najkrótsza droga iteracji ? , pytanie, które jest tutaj, brzmi: Czy jest jakiś powód, dla którego nie widzę tego w C ++? Czy to zła praktyka? aka Dlaczego zawsze widzę kod w C ++, który używa iteratorów podczas iteracjistd::vector
?Odpowiedzi:
Nie. Nie jest to zła praktyka, ale następujące podejście zapewnia Twojemu kodowi pewną elastyczność .
Zwykle kod przed C ++ 11 do iteracji po elementach kontenera używa iteratorów, na przykład:
Dzieje się tak, ponieważ sprawia, że kod jest bardziej elastyczny.
Wszystkie standardowe kontenery bibliotek obsługują i zapewniają iteratory. Jeśli w późniejszym etapie rozwoju będziesz musiał przełączyć się na inny kontener, to ten kod nie musi być zmieniany.
Uwaga: Pisanie kodu, który działa z każdym możliwym kontenerem biblioteki standardowej, nie jest tak łatwe, jak mogłoby się wydawać.
źródło
auto
.Powód, dla którego nie widzisz takiej praktyki, jest dość subiektywny i nie może mieć jednoznacznej odpowiedzi, ponieważ widziałem wiele kodów, które używają wspomnianego sposobu, a nie
iterator
kodu stylu.Oto przyczyny, dla których ludzie nie zastanawiają się nad
vector.size()
sposobem zapętlenia:size()
każdym razem w stanie pętli. Jednak albo nie jest to problem, albo można go w trywialny sposób naprawićstd::for_each()
odfor
samej pętlistd::vector
do drugiego (npmap
,list
) będzie także żądać zmiany mechanizmu pętli, ponieważ nie każdy pojemnik wsparciesize()
styl zapętlenieC ++ 11 zapewnia dobrą możliwość poruszania się po kontenerach. Nazywa się to „pętlą opartą na zakresie dla” (lub „pętlą rozszerzoną dla” w języku Java).
Za pomocą małego kodu możesz przejść przez pełne (obowiązkowe!)
std::vector
:źródło
#pragma omp parallel for
.Najczystszym sposobem iteracji po wektorze są iteratory:
lub (odpowiednik powyższego)
Przed C ++ 0x musisz zamienić auto na typ iteratora i używać funkcji składowych zamiast funkcji globalnych begin i end.
To prawdopodobnie to, co widziałeś. W porównaniu z podejściem, o którym wspomniałeś, zaletą jest to, że nie zależy ci w dużym stopniu od rodzaju
vector
. Jeśli zmieniszvector
klasę na inną „typ kolekcji”, Twój kod prawdopodobnie nadal będzie działał. Możesz jednak zrobić coś podobnego również w Javie. Nie ma dużej różnicy koncepcyjnej; C ++ używa jednak szablonów do zaimplementowania tego (w porównaniu do typów ogólnych w Javie); stąd podejście będzie działać dla wszystkich typów, dla których zdefiniowanobegin
iend
funkcje, nawet dla typów niebędących klasami, takich jak tablice statyczne. Zobacz tutaj: Jak działa na podstawie zakresu dla zwykłych tablic?źródło
begin
i jestend
jednak jednowierszowe.auto
z drugiej strony byłoby dość trudne.Właściwy sposób to:
Gdzie T jest typem klasy wewnątrz wektora. Na przykład, jeśli klasa była CActivity, po prostu napisz CActivity zamiast T.
Ten typ metody będzie działał na każdym STL (nie tylko wektorach, co jest trochę lepsze).
Jeśli nadal chcesz używać indeksów, sposób jest następujący:
źródło
std::vector<T>::size_type
zawszesize_t
? To jest typ, którego zawsze do tego używam.Istnieje kilka ważnych powodów, dla których warto używać iteratorów, z których niektóre zostały wymienione tutaj:
Późniejsza zmiana kontenerów nie powoduje unieważnienia kodu.
tj. jeśli przechodzisz od std :: vector do std :: list lub std :: set, nie możesz użyć indeksów numerycznych, aby uzyskać zawartą w niej wartość. Używanie iteratora jest nadal ważne.
Przechwytywanie nieprawidłowej iteracji w czasie wykonywania
Jeśli zmodyfikujesz kontener w środku pętli, następnym razem, gdy użyjesz iteratora, zgłosi on nieprawidłowy wyjątek iteratora.
źródło
Zaskoczyło mnie, że nikt nie wspomniał, że iteracja przez tablicę z indeksem całkowitoliczbowym ułatwia pisanie błędnego kodu poprzez indeksowanie tablicy z niewłaściwym indeksem. Na przykład, jeśli masz zagnieżdżone pętle używające
i
ij
jako indeksów, możesz nieprawidłowo indeksować tablicęj
zamiast,i
a tym samym wprowadzić błąd do programu.Z drugiej strony inne wymienione tutaj formy, a mianowicie
for
pętla oparta na zakresie i iteratory, są znacznie mniej podatne na błędy. Semantyka języka i mechanizm sprawdzania typu kompilatora zapobiegają przypadkowemu dostępowi do tablicy przy użyciu niewłaściwego indeksu.źródło
W przypadku STL programiści używają
iterators
do przechodzenia przez kontenery, ponieważ iterator jest abstrakcyjną koncepcją zaimplementowaną we wszystkich standardowych kontenerach. Na przykład wstd::list
ogóle nie maoperator []
.źródło
Korzystanie z operatora auto naprawdę ułatwia korzystanie, ponieważ nie trzeba się martwić o typ danych i rozmiar wektora ani żadnej innej struktury danych
Iterowanie wektora przy użyciu pętli auto i for
Wynik:
Możesz również użyć tej metody do iteracji zestawów i list. Korzystanie z opcji auto automatycznie wykrywa typ danych używany w szablonie i umożliwia jego użycie. Tak więc, nawet gdybyśmy mieli składnię
vector
ofstring
lubchar
tę samą, będzie działać dobrzeźródło
Prawidłowy sposób iteracji pętli i wydrukowania jej wartości jest następujący:
źródło
Oto prostszy sposób iteracji i drukowania wartości w wektorze.
źródło
źródło