Używamy typu Integer reprezentują zmienne indeksowe przez większość czasu. Ale w niektórych sytuacjach jesteśmy zmuszeni dokonać wyboru
std::vector<int> vec;
....
for(int i = 0; i < vec.size(); ++i)
....
Spowoduje to, że kompilator wyświetli ostrzeżenie, że mieszane użycie zmiennych podpisanych / niepodpisanych. jeśli zmienię indeks jako for( size_t i = 0; i < vec.size(); i++ )
, (lub an unsigned int
), rozwiąże to problemy.
Jeśli chodzi o bardziej specyficzne użycie typów okien, większość interfejsów API systemu Windows obsługuje DWORD (który jest typowany jako długi bez znaku).
Więc kiedy użyję podobnej iteracji, ponownie spowoduje to samo ostrzeżenie. Teraz, jeśli przepisuję to jako
DWORD dwCount;
....
for(DWORD i = 0; i < dwCount; ++i)
....
Uważam to za trochę dziwne. Może to być problem z postrzeganiem.
Zgadzam się, że powinniśmy używać tego samego typu zmiennej indeksowej, aby uniknąć problemów z zasięgiem w przypadku zmiennych indeksowych. Na przykład jeśli korzystamy
_int64 i64Count; //
....
for(_int64 i = 0; i < i64Count; ++i)
....
Ale w przypadku DWORD lub liczb całkowitych bez znaku występują problemy z przepisaniem go jako
for(int i = 0; (size_t)i < vec.size(); ++i)
Jak większość ludzi pracuje z podobnymi problemami?
std::size_t
ma wyższą rangę niż int (lub nawet długi). Jeśli rozmiar wektora kiedykolwiek przekroczystd::numeric_limits<int>::max()
, będziesz żałować, że użyłeś int.Odpowiedzi:
wektor ma typedef, który mówi prawidłowy typ do użycia: -
Prawie zawsze jest zdefiniowane jako size_t, ale nie możesz na tym polegać
źródło
auto i = 0
? To wcale nie pomaga,i
stań sięint
.using index_t = std::vector<int>::size_type;
.Użyj do tego iteratora, a nie
for
pętli.Dla innych, tak długo, jak typ zmiennej jest tej samej wielkości,
static_cast
powinna działać dobrze (czyliDWORD
doint16_t
)źródło
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i)
jest trudny do napisania. Posiadaniefor (auto i = vec.begin();...
jest o wiele bardziej czytelne. Oczywiścieforeach
jest również w C ++ 11.Opisany przypadek jest również jedną z rzeczy, których nie lubię w C ++. Ale nauczyłem się z tym żyć, używając albo
for( size_t i = 0; i < vec.size(); i++ )
lub
for( int i = 0; i < (int)vec.size(); i++ )
(oczywiście ten ostatni tylko wtedy, gdy nie ma ryzyka uzyskania przelewu int).
źródło
Powodem, dla którego ostrzega przed porównaniem podpisanego i niepodpisanego, jest to, że podpisana wartość prawdopodobnie zostanie przekonwertowana na niepodpisaną, co może nie być tym, czego oczekujesz.
W twoim przykładzie (w porównaniu
int
dosize_t
),int
zostanie domyślnie przekonwertowany nasize_t
(chyba że wint
jakiś sposób ma większy zakres niżsize_t
). Tak więc, jeśli wartośćint
jest ujemna, prawdopodobnie będzie większa niż wartość, z którą ją porównujesz z powodu zawinięcia. Nie będzie to stanowić problemu, jeśli Twój indeks nigdy nie będzie ujemny, ale nadal otrzymasz to ostrzeżenie.Zamiast tego należy użyć typ bez znaku (takiego jak
unsigned int
,size_t
lub, jak zaleca John B ,std::vector<int>::size_type
) dla zmiennej index:Zachowaj ostrożność podczas odliczania:
Powyższe nie zadziała, ponieważ
i >= 0
jest zawsze prawdziwe, gdyi
jest niepodpisane. Zamiast tego użyj „ operatora strzałki ” dla pętli, które odliczają:Jak wskazują inne odpowiedzi, zwykle chcesz użyć iteratora do przejścia przez
vector
. Oto składnia C ++ 11:źródło
unsigned int
nie jest wystarczająco duży, aby pomieścić rozmiar.Nowa opcja dla C ++ 11, możesz wykonywać następujące czynności
for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}
i
for(decltype(dWord) i = 0; i < dWord; ++i) {...}
Chociaż powtarza się nieco więcej niż podstawowa pętla for, nie jest ona tak długa, jak w określaniu wartości sprzed 11 lat, a konsekwentne stosowanie tego wzorca będzie działać dla większości, jeśli nie wszystkich, możliwych terminów chcesz porównać z tym, co czyni go doskonałym do refaktoryzacji kodu. Działa nawet w takich prostych przypadkach:
int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)
Ponadto, chociaż powinieneś używać,
auto
gdy ustawiaszi
jakąś inteligentną wartość (np.vec.begin()
),decltype
Działa, gdy ustawiasz na stałą taką jak zero, gdzie auto po prostu to rozwiązuje,int
ponieważ 0 jest prostym dosłunkiem całkowitym.Szczerze mówiąc, chciałbym zobaczyć mechanizm kompilatora do rozszerzania
auto
określania typu dla inkrementatorów pętli, aby spojrzeć na porównywaną wartość.źródło
Używam obsady do int, jak w
for (int i = 0; i < (int)v.size(); ++i)
. Tak, to brzydkie. Obwiniam to za głupi projekt standardowej biblioteki, w której postanowiono użyć liczb całkowitych bez znaku do przedstawienia rozmiarów. (Aby ... co? Rozszerzyć zasięg o jeden bit?)źródło
if(v.size()-1 > 0) { ... }
zwrócenie wartości true dla pustego pojemnika? Problem polega na tym, że rozmiary są również często używane w arytmetyce, szczególnie. z kontenerami opartymi na indeksach, które proszą o problemy, biorąc pod uwagę, że są niepodpisane. Zasadniczo używanie typów niepodpisanych do celów innych niż 1) bitowe manipulacje lub 2) arytmetyka modularna wymaga kłopotów.if(v.size() > 1) { ... }
ponieważ to wyjaśnia intencję, a jako dodatkowy bonus kwestia podpisania / niepodpisania staje się nieważna), ale widzę, jak w niektórych szczególnych przypadkach sygnatura może być przydatna. Poprawiono mnie.