Załóżmy, że masz następującą for
pętlę *:
for (int i = 0; i < 10; ++i) {
// ...
}
który zwykle można również zapisać jako:
for (int i = 0; i != 10; ++i) {
// ...
}
Końcowe wyniki są takie same, więc czy są jakieś rzeczywiste argumenty przemawiające za stosowaniem jednego? Osobiście używam tego pierwszego na wypadek, gdyby i
z jakiegoś powodu szaleje i pomija wartość 10.
* Przepraszam za użycie magicznych liczb, ale to tylko przykład.
int i = 10; while(i --> 0) { /* stuff */ }
while ((i--) > 0)
Odpowiedzi:
Powodem wyboru jednego lub drugiego jest zamiar, w wyniku czego zwiększa on czytelność .
Cel: pętla powinna działać tak długo, jak
i
jest mniejsza niż 10, nie tak długo, jaki
nie jest równa 10. Nawet jeśli ta ostatnia może być taka sama w tym konkretnym przypadku, to nie to, co masz na myśli, więc nie powinna być tak napisanym.Czytelność: dzięki zapisaniu tego, co masz na myśli, łatwiej jest to zrozumieć. Na przykład, jeśli użyjesz
i != 10
, ktoś czytający kod może zastanawiać się, czy wewnątrz pętli jest jakiś sposób,i
aby stać się większy niż 10 i że pętla powinna być kontynuowana (btw: zły styl to bałagan z iteratorem gdzie indziej niż w nagłówkufor
-statement, ale to nie oznacza, że ludzie nie rób tego w wyniku czego oczekują opiekunowie).źródło
i
jest „mniejsza niż 10”, powinna działać tak długo, jak długo (w tym przypadku) górna granica nie zostanie osiągnięta. Kiedy używasz uzasadnienia przedziału / iteratora C ++, o wiele bardziej logiczne jest wyrażanie tego za pomocą!=
niż<
.<
faktycznie wyraża to dokładnie.for
pętli. Używanie<
tutaj byłoby głupie. Wydaje się, że Deckard to potwierdza. Bardzo zgadzam się z jego komentarzem w odpowiedzi na mój.!=
<
Wzór jest ogólnie użyteczny nawet jeśli przyrost nie dzieje się dokładnie 1.Pozwala to na jeden wspólny sposób wykonywania pętli, niezależnie od tego, jak to się faktycznie robi.
źródło
i
na modyfikację wewnątrz pętli całkowicie bezpiecznie, jeśli zajdzie taka potrzeba.<
, takie jak iteratory w sekwencji, a więc!=
byłby to jeden wspólny sposób wykonywania pętli w C ++.<
wzorem, ponieważ wymaga jednego naciśnięcia klawisza zamiast dwóch z>
wzorcem i czterech z!=
. To naprawdę kwestia wydajności podobnej do OCD.W C ++ zaleceniem Scotta Myersa w bardziej efektywnym C ++ (pozycja 6) jest zawsze używanie drugiego, chyba że masz ku temu powód, ponieważ oznacza to, że masz tę samą składnię dla indeksów iteratora i liczb całkowitych, dzięki czemu możesz bezproblemowo przełączać się między
int
iteratorem bez żadnych zmian w składni.W innych językach nie ma to zastosowania, więc myślę, że
<
jest to raczej preferowane ze względu na punkt Thorbjørna Ravna Andersena.Nawiasem mówiąc, pewnego dnia rozmawiałem o tym z innym deweloperem, a on powiedział, że powodem, dla którego wolałbym
<
więcej,!=
jest to, żei
może przypadkowo zwiększyć o więcej niż jeden, a to może spowodować, że warunek przerwania nie będzie spełniony; to jest IMO ładunek nonsensów.źródło
<
bardziej defensywne programowanie niż!=
wtedy ...<
jest bardziej defensywny, a moi koledzy go nienawidzą, jeśli piszę,!=
więc tego nie robię. Jednak jest coś!=
w C ++ i właśnie to przedstawiłem.i++
jest zmiana pętli while w pętlę for. Nie jestem jednak pewien, czy posiadanie połowy liczby iteracji jest lepsze niż (prawie) nieskończona pętla; ten drugi prawdopodobnie uczyniłby błąd bardziej oczywistym.Używanie (i <10) jest moim zdaniem bezpieczniejszą praktyką. Łapie maksymalną liczbę potencjalnych przypadków rezygnacji - wszystko, co jest większe lub równe 10. Porównaj to z drugim przypadkiem (i! = 10); wyłapuje tylko jeden możliwy przypadek rzucenia - gdy i ma dokładnie 10 lat.
Produktem ubocznym tego jest to, że poprawia czytelność. Dodatkowo, jeśli przyrost będzie wynosił cokolwiek innego 1, może pomóc zminimalizować prawdopodobieństwo wystąpienia problemu, gdybyśmy popełnili błąd podczas pisania sprawy zamykającej.
Rozważać:
Chociaż oba przypadki są prawdopodobnie wadliwe / błędne, drugi może być WIĘCEJ błędny, ponieważ nie zostanie zamknięty. Pierwszy przypadek zostanie zakończony i istnieje większa szansa, że zakończy się w odpowiednim miejscu, mimo że 14 to prawdopodobnie niewłaściwa liczba (15 prawdopodobnie byłoby lepsze).
źródło
Oto kolejna odpowiedź, której nikt jeszcze nie wymyślił.
for
pętle powinny być używane, gdy trzeba iterować po sekwencji . Użycie!=
jest najbardziej zwięzłą metodą określenia warunku zakończenia pętli. Jednak stosowanie mniej restrykcyjnego operatora jest bardzo powszechnym idiomem programowania obronnego. Dla liczb całkowitych nie ma to znaczenia - jest to tylko osobisty wybór bez bardziej szczegółowego przykładu. Pętle nad kolekcjami z iteratorami, których chcesz używać!=
z powodów, które podali inni. Jeśli weźmiesz pod uwagę sekwencjefloat
lubdouble
, to chcesz uniknąć!=
za wszelką cenę.Chciałem zwrócić uwagę, że
for
jest używany, gdy trzeba iterować sekwencję. Wygenerowana sekwencja ma punkt początkowy, odstęp i warunek zakończenia. Są one zwięźle określone wfor
instrukcji. Jeśli okaże się, że (1) nie obejmuje części krokowejfor
lub (2) określając coś w rodzajutrue
warunku ochronnego, nie powinieneś używaćfor
pętli!while
Pętla służy do kontynuowania pracy, gdy warunek jest spełniony specyficzny. Jeśli nie przetwarzasz sekwencji, prawdopodobniewhile
zamiast tego potrzebujesz pętli. Argumenty warunku ochronnego są tutaj podobne, ale decyzja między pętląwhile
afor
pętlą powinna być bardzo świadoma.while
Pętli pod cenione w środowisku C ++ MOM.Jeśli przetwarzasz kolekcję przedmiotów (bardzo częste
for
użycie pętli), naprawdę powinieneś użyć bardziej specjalistycznej metody. Niestetystd::for_each
jest dość bolesny w C ++ z wielu powodów. W wielu przypadkach oddzielenie korpusufor
pętli w funkcji wolnostojącej (choć nieco bolesne) skutkuje znacznie czystszym rozwiązaniem. Podczas pracy ze zbiorami, należy rozważyćstd::for_each
,std::transform
czystd::accumulate
. Implementacja wielu algorytmów staje się zwięzła i krystalicznie czysta, gdy jest wyrażana w ten sposób. Nie wspominając już o tym, że izolowanie ciała pętli w oddzielną funkcję / metodę zmusza cię do skoncentrowania się na algorytmie, jego wymaganiach wejściowych i wynikach.Jeśli używasz Java, Python, Ruby, a nawet C ++ 0x , powinieneś używać odpowiedniej pętli foreach kolekcji . Gdy kompilatory C ++ implementują tę funkcję, wiele
for
pętli zniknie, podobnie jak tego rodzaju dyskusje.źródło
while
,for
iforeach
(lub język equivilant)while
<
) lub operator jest łagodny w wartościach, które zawodzi (!=
).Używając „mniej niż” jest (zazwyczaj) poprawne semantycznie, naprawdę masz na myśli odliczanie, aż
i
nie będzie już mniej niż 10, więc „mniej niż” jasno wyraża twoje intencje. Użycie „nierównomiernego” oczywiście działa praktycznie w przypadkach wywołań, ale ma nieco inne znaczenie. W niektórych przypadkach może to być potrzebne, ale z mojego doświadczenia nigdy tak nie było. Jeśli naprawdę masz przypadek, w którymi
może być więcej lub mniej niż 10, ale chcesz nadal zapętlać, aż będzie równy 10, wtedy ten kod naprawdę będzie wymagał bardzo wyraźnego komentarza i prawdopodobnie mógłby być napisany przy użyciu innej konstrukcji, takiej jakwhile
być może jako pętla.źródło
Jednym z powodów, dla których wolałbym więcej
less than
niż,not equals
jest działanie jako strażnik. W niektórych ograniczonych okolicznościach (złe programowanie lub odkażanie)not equals
można to pominąćless than
, ale nadal będzie obowiązywać.Oto jeden przykład, w którym brak kontroli odkażania doprowadził do dziwnych wyników: http://www.michaeleisen.org/blog/?p=358
źródło
Oto jeden z powodów, dla których wolisz używać
<
zamiast!=
. Jeśli używasz języka z zasięgiem zmiennych globalnych, co się stanie, jeśli zmodyfikuje się inny kodi
? Jeśli używasz<
raczej niż!=
, najgorsze, co się dzieje, to to, że iteracja kończy się szybciej: być może niektóre inne inkrementy kodui
przypadkowo i pomijasz kilka iteracji w pętli for. Ale co się stanie, jeśli zapętlisz od 0 do 10, a pętla dojdzie do 9, a niektóre źle napisane przyrosty wątkówi
z jakiegoś dziwnego powodu. Następnie twoja pętla kończy iterację i przyrosty,i
tak że wartość wynosi teraz 11. Ponieważ pętla pominęła warunek wyjścia (i
nigdy nie równa się 10), teraz zapętla się w nieskończoność.Nie musi to być szczególnie dziwaczna logika typu wątkowość i zmienne globalne, które to powoduje. Być może piszesz pętlę, która wymaga powrotu. Jeśli mutujesz
i
wewnątrz pętli i psujesz swoją logikę, mając ją tak, że ma ona górną granicę, a nie!=
jest mniej prawdopodobne, że pozostawi cię w nieskończonej pętli.źródło
W świecie osadzonym, szczególnie w hałaśliwym otoczeniu, nie można liczyć na to, że pamięć RAM koniecznie zachowuje się tak, jak powinna. W warunkowym (dla, podczas gdy, jeśli) porównywaniu za pomocą „==” lub „! =” Zawsze ryzykujesz, że twoje zmienne pominą tę kluczową wartość, która kończy pętlę - może to mieć katastrofalne konsekwencje - Mars Lander konsekwencje poziomu. Użycie „<” lub „>” w tym stanie zapewnia dodatkowy poziom bezpieczeństwa w celu wychwycenia „nieznanych niewiadomych”.
W oryginalnym przykładzie, gdyby
i
były niewytłumaczalnie katapultowane do wartości znacznie większej niż 10, porównanie „<” natychmiast wychwyciłoby błąd i opuścił pętlę, ale „! =” Kontynuowałoby odliczanie do momentui
zawinięcia wokół 0 i wstecz do 10.źródło
for (i=4; i<length; i++) csum+=dat[i];
przypadku, gdy prawidłowe pakiety zawsze miałybylength
co najmniej cztery, ale jeden może otrzymywać uszkodzone pakiety. Jeśli różne typy pakietów mają różne wymagania dotyczące długości, można sprawdzić poprawność długości w ramach przetwarzania, która jest inna dla każdego typu pakietu, ale najpierw sprawdzić poprawność sumy kontrolnej w ramach wspólnej logiki. Jeśli zostanie odebrany pakiet niedostatecznej długości, tak naprawdę nie ma znaczenia, czy obliczenie sumy kontrolnej zgłasza „dobre” czy „złe”, ale nie powinno się zawiesić.