Jaki jest prawidłowy sposób iteracji po wektorze w C ++?
Rozważ te dwa fragmenty kodu, ten działa dobrze:
for (unsigned i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
i ten:
for (int i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
który generuje warning: comparison between signed and unsigned integer expressions
.
Jestem nowy w świecie C ++, więc unsigned
zmienna wygląda dla mnie trochę przerażająco i wiem, że unsigned
zmienne mogą być niebezpieczne, jeśli nie zostaną właściwie użyte, więc - czy to prawda?
.size()
nie jest typuunsigned
akaunsigned int
. To rodzajstd::size_t
.std::size_t
to typedef zdefiniowany przez wdrożenie. Zobacz standard.std::size_t
może być równoważne zunsigned
bieżącą implementacją, ale to nie jest istotne. Udawanie, że tak jest, może skutkować nieprzenośnym kodem i niezdefiniowanym zachowaniem.std::size_t
w praktyce. Czy uważasz, że omawialiśmy już wszystko w tym szalonym strumieniu komentarzy przez 6 lat?Odpowiedzi:
W celu powtórzenia wstecz zobacz tę odpowiedź .
Iteracja do przodu jest prawie identyczna. Wystarczy zmienić przyrost iteratorów / swapów przyrostowych. Powinieneś preferować iteratory. Niektóre osoby mówią, aby użyć
std::size_t
jako typu zmiennej indeksu. Nie jest to jednak przenośne. Zawsze używajsize_type
typedef kontenera (chociaż możesz uciec tylko z konwersją w przypadku iteracji do przodu, może tak naprawdę pójść nie tak w przypadku przypadku iteracji do tyłustd::size_t
, jeślistd::size_t
jest szerszy niż typefsize_type
) :Używanie std :: vector
Korzystanie z iteratorów
Ważne jest, aby zawsze używać iteratorów, których definicji nie znasz. To zapewni, że Twój kod będzie działał jak najbardziej ogólny.
Korzystanie z zakresu C ++ 11
Korzystanie z indeksów
Korzystanie z tablic
Korzystanie z iteratorów
Korzystanie z zakresu C ++ 11
Korzystanie z indeksów
Przeczytaj w odpowiedzi na iterację wsteczną, jaki problem
sizeof
może przynieść to podejście.źródło
for (auto p : polygon){sum += p;}
Minęły cztery lata, Google dał mi tę odpowiedź. W przypadku standardowego C ++ 11 (znanego również jako C ++ 0x ) istnieje nowy przyjemny sposób (za cenę zerwania wstecznej kompatybilności): nowe
auto
słowo kluczowe. To oszczędza ci bólu związanego z jawnym określaniem typu iteratora, który ma być używany (powtarzanie typu wektora ponownie), gdy jest oczywiste (dla kompilatora), jakiego typu użyć. Zv
bycia swojejvector
, można zrobić coś takiego:C ++ 11 idzie jeszcze dalej i daje specjalną składnię do iteracji po kolekcjach takich jak wektory. Eliminuje to konieczność pisania rzeczy, które zawsze są takie same:
Aby zobaczyć to w działającym programie, skompiluj plik
auto.cpp
:Pisząc to, kompilując to z g ++ , zwykle musisz ustawić go do pracy z nowym standardem, podając dodatkową flagę:
Teraz możesz uruchomić przykład:
Należy pamiętać, że instrukcje dotyczące kompilowania i uruchamiania są specyficzne dla kompilatora gnu c ++ w systemie Linux , program powinien być niezależny od platformy (i kompilatora).
źródło
for (auto& val: vec)
std::vector<int> v = std::vector<int>();
, czy mógłbyś po prostu użyćstd::vector<int> v;
zamiast tego?W konkretnym przypadku w twoim przykładzie użyłbym algorytmów STL, aby to osiągnąć.
W przypadku bardziej ogólnego, ale wciąż dość prostego przypadku, wybrałbym:
źródło
Odnośnie odpowiedzi Johannesa Schauba:
Może to działać z niektórymi kompilatorami, ale nie z gcc. Problem polega na tym, czy std :: vector :: iterator jest typem, zmienną (członkiem) lub funkcją (metodą). W przypadku gcc pojawia się następujący błąd:
Rozwiązaniem jest użycie słowa kluczowego „typename”, jak powiedziano:
źródło
T
to tylko argumentu szablonu, a zatem wyrażeniestd::vector<T*>::iterator
jest nazwą zależną. Aby nazwa zależna była analizowana jako typ, musi być poprzedzonatypename
słowem kluczowym, jak wskazuje diagnostyka.Wywołanie w celu
vector<T>::size()
zwrócenia wartości typustd::vector<T>::size_type
, a nie int, unsigned int lub w inny sposób.Również ogólnie iteracja nad kontenerem w C ++ odbywa się za pomocą iteratorów , takich jak ten.
Gdzie T to typ danych przechowywanych w wektorze.
Lub przy użyciu różnych algorytmów iteracji (
std::transform
,std::copy
,std::fill
,std::for_each
i tak dalej).źródło
Użyj
size_t
:Cytując Wikipedię :
źródło
#include <cstddef>
raczej, zamiast,<stddef.h>
lub, co gorsza, całość[c]stdlib
i używaćstd::size_t
zamiast wersji niekwalifikowanej - i to samo dla każdej innej sytuacji, w której masz wybór pomiędzy<cheader>
i<header.h>
.Trochę historii:
Aby pokazać, czy liczba jest ujemna, czy nie, użyj bitu „znakowego”.
int
jest podpisanym typem danych, co oznacza, że może przechowywać wartości dodatnie i ujemne (około -2 miliardy do 2 miliardów).Unsigned
może przechowywać tylko liczby dodatnie (a ponieważ nie marnuje trochę na metadane, może przechowywać więcej: 0 do około 4 miliardów).std::vector::size()
zwraca anunsigned
, bo jak wektor może mieć długość ujemną?Ostrzeżenie mówi ci, że prawy operand twojej deklaracji nierówności może pomieścić więcej danych niż lewy.
Zasadniczo, jeśli masz wektor z ponad 2 miliardami pozycji i używasz liczby całkowitej do indeksowania, natrafisz na problemy z przepełnieniem (int zawróci do ujemnych 2 miliardów).
źródło
Zwykle używam BOOST_FOREACH:
Działa na kontenerach STL, tablicach, ciągach w stylu C itp.
źródło
Aby być kompletnym, składnia C ++ 11 umożliwia tylko jedną kolejną wersję iteratorów ( ref ):
Co jest również wygodne w przypadku iteracji odwrotnej
źródło
W C ++ 11
Użyłbym ogólnych algorytmów, takich jak
for_each
unikanie wyszukiwania odpowiedniego typu iteratora i wyrażenia lambda, aby uniknąć dodatkowych nazwanych funkcji / obiektów.Krótki „ładny” przykład dla konkretnego przypadku (zakładając, że wielokąt jest wektorem liczb całkowitych):
testowane na: http://ideone.com/i6Ethd
Nie zapomnij podać: algorytmu i, oczywiście, wektora :)
Microsoft ma też ładny przykład:
źródło: http://msdn.microsoft.com/en-us/library/dd293608.aspx
źródło
źródło
Pierwszy to poprawny typ i poprawny w pewnym ścisłym znaczeniu. (Jeśli myślisz o tym, rozmiar nigdy nie może być mniejszy niż zero.) To ostrzeżenie uderza mnie jako jednego z dobrych kandydatów do bycia ignorowanym.
źródło
i == INT_MAX
, wówczasi++
powoduje niezdefiniowane zachowanie. W tym momencie wszystko może się zdarzyć.Zastanów się, czy w ogóle potrzebujesz iteracji
<algorithm>
Standardowy nagłówek dostarcza nam urządzeń do tego:Inne funkcje w bibliotece algorytmów wykonują typowe zadania - upewnij się, że wiesz, co jest dostępne, jeśli chcesz zaoszczędzić wysiłku.
źródło
Niewyraźny, ale ważny szczegół: jeśli powiesz „for (auto it)” w następujący sposób, otrzymasz kopię obiektu, a nie rzeczywisty element:
Aby zmodyfikować elementy wektora, musisz zdefiniować iterator jako odniesienie:
źródło
Jeśli Twój kompilator to obsługuje, możesz użyć zakresu opartego na dostęp do elementów wektorowych:
Wydruki: 1 2 3. Uwaga: nie można użyć tej techniki do zmiany elementów wektora.
źródło
Dwa segmenty kodu działają tak samo. Jednak niepodpisana int int jest poprawna. Użycie typów int bez znaku będzie działało lepiej z wektorem w użytej instancji. Wywołanie funkcji elementu size () w wektorze zwraca wartość całkowitą bez znaku, więc chcesz porównać zmienną „i” do wartości własnego typu.
Ponadto, jeśli nadal jesteś trochę zaniepokojony tym, jak w kodzie wygląda „unsigned int”, spróbuj „uint”. Jest to w zasadzie skrócona wersja „unsigned int” i działa dokładnie tak samo. Nie musisz także dołączać innych nagłówków, aby z niego korzystać.
źródło
Dodając to, ponieważ nie znalazłem tego w żadnej odpowiedzi: w przypadku iteracji opartej na indeksie możemy użyć parametru,
decltype(vec_name.size())
który oceniastd::vector<T>::size_type
Przykład
źródło