Czytam notatki z wykładu mojego wykładowcy C ++, który napisał:
- Użyj wcięcia // OK
- Nigdy nie polegaj na pierwszeństwie operatora - zawsze używaj nawiasów // OK
- Zawsze używaj bloku {} - nawet dla pojedynczej linii // nie OK , dlaczego ???
- Stały obiekt po lewej stronie porównania // OK
- Użyj bez znaku dla zmiennych, które są> = 0 // fajna sztuczka
- Ustaw wskaźnik na NULL po usunięciu - Podwójna ochrona przed usunięciem // nieźle
Trzecia technika nie jest dla mnie jasna: co zyskałbym, umieszczając jedną linię w { ... }
?
Weźmy na przykład ten dziwny kod:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
if (i % 2 == 0)
{
j++;
}
}
i zamień na:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
if (i % 2 == 0)
j++;
Jakie są zalety korzystania z 1. wersji?
for (unsigned i = 100; i >= 0; --i)
.(i % 2 == 0)
zaprzecza (2). Polegasz na pierwszeństwie operatora, a znaczenie jest oczywiście((i % 2) == 0)
raczej niż(i % (2 == 0))
. Sklasyfikowałbym zasadę 2 jako „prawidłowy sentyment, ale„ zawsze ”jest zły”.Odpowiedzi:
Spróbujmy również zmodyfikować,
i
gdy będziemy zwiększaćj
:O nie! Pochodzący z Pythona wygląda to dobrze, ale w rzeczywistości tak nie jest, ponieważ jest równoważne z:
Oczywiście jest to głupi błąd, ale może popełnić go nawet doświadczony programista.
Kolejny bardzo dobry powód jest wskazany w odpowiedzi ta.speot.is .
Trzeci , o którym myślę, to zagnieżdżony
if
:Załóżmy, że chcesz teraz,
doSomethingElse()
kiedycond1
nie jest spełniony (nowa funkcja). Więc:co jest oczywiście błędne, ponieważ
else
wiąże się z wewnętrznymif
.Edycja: Ponieważ przyciąga to trochę uwagi, wyjaśnię swój pogląd. Pytanie, na które odpowiadałem to:
Które opisałem. Istnieje kilka korzyści. Ale IMO zasady „zawsze” nie zawsze mają zastosowanie. Więc nie w pełni popieram
Nie mówię, że zawsze używaj
{}
bloku. Jeśli jest to dość prosty warunek i zachowanie, nie rób tego. Jeśli podejrzewasz, że ktoś może przyjść później i zmienić kod, aby dodać funkcjonalność, zrób to.źródło
i++
wcześniejj++
, obie zmienne będą nadal w zasięgu, gdy zostaną użyte.i++;
w sposób, który natychmiast pokazuje, że nie jest on częścią pętli. (W przeszłości mógł to być rozsądny argument i widziałem takie problemy. Około 20 lat temu. Od tamtej pory.)Bardzo łatwo jest przypadkowo zmienić przepływ kontroli z komentarzami, jeśli nie używasz
{
i}
. Na przykład:Jeśli skomentujesz komentarz
do_something_else()
z jednym wierszem, skończysz na tym:Kompiluje się, ale
must_always_do_this()
nie zawsze jest wywoływane.Mamy ten problem w naszej bazie kodu, gdzie ktoś wszedł, aby bardzo szybko wyłączyć niektóre funkcje przed wydaniem. Na szczęście złapaliśmy go podczas przeglądu kodu.
źródło
must_always_do_this();
zostanie wykonane, jeśli skomentujesz // do_something_else ();if(debug) \n //print(info);
. Zasadniczo wyjęłam całą bibliotekę.Fortunately we caught it in code review.
Auć! To brzmi tak źle.Fortunately we caught it in unit tests.
byłoby znacznie lepiej!Mam wątpliwości co do kompetencji wykładowcy. Biorąc pod uwagę jego punkty:
(b*b) - ((4*a)*c)
? Niektóre pierwszeństwa są oczywiste (lub powinny być), a dodatkowe nawiasy tylko powodują zamieszanie. (Z drugiej strony, powinieneś używać nawiasów w mniej oczywistych przypadkach, nawet jeśli wiesz, że nie są one potrzebne).{
nie jest aż tak widoczny, więc najlepiej założyć, że zawsze tam jest. W drugim przypadku ja (i większość osób, z którymi pracowałem) nie mam problemu z pominięciem nawiasów klamrowych dla pojedynczej instrukcji. (Pod warunkiem, oczywiście, że wcięcie jest systematyczne i że konsekwentnie używasz tego stylu. (I wielu bardzo dobrych programistów, piszących bardzo czytelny kod, pomija nawiasy klamrowe nawet przy pierwszym formatowaniu).if ( NULL == ptr )
są wystarczająco brzydkie, aby utrudnić czytelność. Pisz porównania intuicyjnie. (Co w wielu przypadkach powoduje stałą po prawej.) Jego 4 to zła rada; wszystko, co czyni kod nienaturalnym, czyni go mniej czytelnym.int
jest zastrzeżone dla szczególnych przypadków. Dla doświadczonych programistów C i C ++ użycieunsigned
operatorów bitów sygnałów. C ++ nie ma prawdziwego typu kardynalnego (ani żadnego innego efektywnego typu podzakresu);unsigned
nie działa dla wartości liczbowych z powodu reguł promocji. Prawdopodobnie mogłyby to być wartości liczbowe, dla których żadne operacje arytmetyczne nie miałyby sensu, takie jak numery seryjneunsigned
. Byłbym jednak przeciw temu, ponieważ wysyła niewłaściwy komunikat: operacje bitowe również nie mają sensu. Podstawową zasadą jest to, że typy całkowe sąint
, o ile nie ma istotnego powodu, aby używać innego typu.delete this;
często jest najczęstszy przypadek (i nie można ustawićthis
doNULL
), a inaczej, najbardziejdelete
są destruktory, więc nie można uzyskać dostępu wskaźnik później tak. Ustawienie tej opcjiNULL
nie ma wpływu na żadne inne wskaźniki unoszące się wokół. Systematyczne ustawianie wskaźnikaNULL
daje fałszywe poczucie bezpieczeństwa i tak naprawdę nic nie kupuje.Spójrz na kod w jednym z typowych odniesień. Stroustrup narusza każdą podaną przez ciebie regułę, z wyjątkiem pierwszej, na przykład.
Proponuję znaleźć innego wykładowcę. Ten, który tak naprawdę wie o czym mówi.
źródło
delete this
, czy to jest bardziej powszechne niż widziałem? Nie wydaje mi się, aby ustawianie wskaźnika na NULL po użyciu jest tak kiepską rzeczą, jak YMMV. Może to tylko ja, ale większość jego wskazówek nie wydaje się taka zła.if (ptr = NULL)
chyba że napiszesz to jakoif ((ptr = NULL))
. Muszę zgodzić się z Jamesem Kanze, że brzydota, jaką jest posiadanie,NULL
sprawia, że jest to zdecydowanie NIE dla mnie.unsigned
wskazuje na dążenie ze strony programisty, że zmienna powinna reprezentować tylko liczby dodatnie. Mieszanie z podpisanymi liczbami zwykle powoduje ostrzeżenie kompilatora, które prawdopodobnie było tym, czego zamierzał wykładowca.size_t
ktoś?Wszystkie pozostałe odpowiedzi bronią zasady twojego wykładowcy 3.
Powiem, że się z tobą zgadzam: zasada jest zbędna i nie radziłbym jej. To prawda, że teoretycznie zapobiega błędom, jeśli zawsze dodajesz nawiasy klamrowe. Z drugiej strony nigdy nie spotkałem tego problemu w prawdziwym życiu : wbrew temu, co sugerują inne odpowiedzi, nie zapomniałem dodać nawiasów klamrowych, gdy stały się konieczne. Jeśli użyjesz odpowiedniego wcięcia, natychmiast stanie się oczywiste, że musisz dodać nawiasy klamrowe po wcięciu więcej niż jednego wyrażenia.
Odpowiedź „komponentu 10” w rzeczywistości podkreśla jedyny możliwy przypadek, w którym może to naprawdę prowadzić do błędu. Ale z drugiej strony zastąpienie kodu wyrażeniem regularnym zawsze wymaga ogromnej uwagi.
Spójrzmy teraz na drugą stronę medalu: czy jest wada, aby zawsze używać nawiasów klamrowych? Inne odpowiedzi po prostu ignorują ten punkt. Ale jest to wadą: to zajmuje dużo przestrzeni pionowej ekranu, a to z kolei może spowodować, że kod nieczytelny, ponieważ oznacza to, że trzeba przejść więcej niż to konieczne.
Rozważ funkcję z wieloma klauzulami ochronnymi na początku (i tak, poniższy kod jest zły C ++, ale w innych językach byłaby to dość powszechna sytuacja):
To okropny kod i zdecydowanie argumentuję, że następujące elementy są znacznie bardziej czytelne:
Podobnie krótkie zagnieżdżone pętle korzystają z pominięcia nawiasów klamrowych:
Porównać z:
Pierwszy kod jest zwięzły; drugi kod jest wzdęty.
I tak, można to w pewnym stopniu złagodzić, umieszczając nawias otwierający w poprzedniej linii. Ale tak by było było byłoby mniej czytelne niż kod bez nawiasów klamrowych.
W skrócie: nie pisz niepotrzebnego kodu, który zajmuje miejsce na ekranie.
źródło
if (a == nullptr) { throw null_ptr_error("a"); }
w jednym wierszu.Baza kodu, nad którym pracuję, jest rozproszona z kodem przez ludzi z patologiczną niechęcią do nawiasów klamrowych, a dla ludzi, którzy przyjdą później, naprawdę może to mieć wpływ na łatwość konserwacji.
Najczęstszym problematycznym przykładem, z jakim się spotkałem, jest:
Więc kiedy przychodzę i chcę dodać oświadczenie wtedy, mogę z łatwością skończyć z tym, jeśli nie jestem ostrożny:
Biorąc pod uwagę, że dodanie nawiasów zajmuje ~ 1 sekundę i może zaoszczędzić co najmniej kilka zdezorientowanych minut debugowania, dlaczego nigdy nie miałbyś skorzystać z opcji zmniejszonej dwuznaczności? Wydaje mi się to fałszywą ekonomią.
źródło
if(really long...editor){ do_foo;}
czemu unikniesz tego przypadku? Wydaje się, że problem nadal będzie taki sam. Osobiście wolę unikać nawiasów klamrowych, gdy nie jest to konieczne, ale nie ma to nic wspólnego z czasem potrzebnym na ich napisanie, ale zmniejszoną czytelnością z powodu dwóch dodatkowych wierszy w kodzieMój 2c:
Oczywiście
Nie używałbym słów „nigdy” i „zawsze”, ale ogólnie rzecz biorąc widzę, że ta zasada jest przydatna. W niektórych językach (Lisp, Smalltalk) nie jest to problemem.
Nigdy tego nie robię i nigdy nie miałem ani jednego problemu, ale widzę, jak to może być dobre dla studentów, szczególnie. jeśli wcześniej studiowali Python.
Warunki Yoda? Nie prosze Utrudnia to czytelność. Wystarczy użyć maksymalnego poziomu ostrzeżenia podczas kompilacji kodu.
OK. Zabawne, słyszałem, że Stroustrup się nie zgadza.
Zła rada! Nigdy nie używaj wskaźnika, który wskazuje na usunięty lub nieistniejący obiekt.
źródło
unsigned
zepsuty”, jednym z problemów jest to, że gdy C ++ porównuje typy podpisane i niepodpisane o podobnej wielkości, przed dokonaniem porównania konwertuje się na niepodpisane . Co powoduje zmianę wartości. Konwersja na podpisane niekoniecznie byłaby lepsza; porównanie powinno naprawdę odbywać się „tak jakby” obie wartości zostały przekonwertowane na większy typ, który mógłby reprezentować wszystkie wartości w każdym typie.unsigned
. Jestem pewien, że nie ma problemu zeexp(double)
zwrotem wartości większej niżMAX_INT
:-). Ale po raz kolejny prawdziwym problemem są niejawne konwersje.int i = exp( 1e6 );
jest całkowicie poprawnym C ++. W pewnym momencie Stroustrup zaproponował wycofanie stratnych, ukrytych konwersji, ale komitet nie był zainteresowany. (Interesującym pytanie: czyunsigned
->int
uznać stratny Pomyślę obu.unsigned
->int
aint
->unsigned
stratne Które przejść długą drogę do podejmowania.unsigned
OKjest bardziej intuicyjny i łatwo zrozumiały. Wyjaśnia to intencję.
I zapewnia, że kod nie zostanie złamany, gdy nowy użytkownik może nieświadomie przegapić
{
,}
dodając nową instrukcję kodu.źródło
Makes the intent clear
+1, to prawdopodobnie najbardziej zwięzły i dokładny powód.Aby dodać do bardzo rozsądnych sugestii powyżej, jeden przykład, który napotkałem podczas refaktoryzacji kodu, w którym staje się on krytyczny, był następujący: Zmieniłem bardzo dużą bazę kodu, aby przełączyć się z jednego interfejsu API na inny. Pierwszy interfejs API miał wywołanie w celu ustawienia identyfikatora firmy w następujący sposób:
mając na uwadze, że wymiana wymagała dwóch połączeń:
Zacząłem to zmieniać za pomocą wyrażeń regularnych, co było bardzo udane. Przekazaliśmy również kod przez astyle , co naprawdę uczyniło go o wiele bardziej czytelnym. Następnie, w połowie procesu recenzji, odkryłem, że w pewnych warunkowych okolicznościach zmienia to:
Do tego:
co wyraźnie nie jest tym, co było wymagane. Musiałem wrócić do początku, zrób to jeszcze raz, traktując zamiennik jako całkowicie w bloku, a następnie ręcznie zmieniając wszystko, co skończyło się na głupkowatym (przynajmniej nie byłoby to nieprawidłowe).
Zauważam, że astyle ma teraz opcję,
--add-brackets
która pozwala dodawać nawiasy kwadratowe tam, gdzie ich nie ma, i zdecydowanie polecam to, jeśli kiedykolwiek znajdziesz się w tej samej pozycji, co ja.źródło
#define FOO() func1(); \ func2();
(z podziałem wiersza po odwrotnym ukośniku), to samo dotyczy wyszukiwania i zamiany. To powiedziawszy, widziałem „zawsze używaj nawiasów klamrowych” jako regułę stylu właśnie dlatego, że nie pozwala ci to na zawijanie wszystkich makr z wieloma wyrażeniamido .. while(0)
. Ale nie zgadzam się.inline
), prawdopodobnie powinieneś dążyć do tego, aby działały jak najbardziej jak to możliwe, używającdo { ... } while(0)
sztuczki, jeśli to konieczne (i wiele dodatkowych nawiasów. Ale to nadal by nie nie powstrzymam cię od używania aparatów ortodontycznych wszędzie, jeśli taki jest styl domu. (FWIW: Pracowałem w miejscach o różnych stylach domów, obejmujących wszystkie omówione tutaj style. Nigdy nie uważałem, że to poważny problem).Używam
{}
wszędzie, z wyjątkiem kilku przypadków, w których jest to oczywiste. Jedna linia to jeden z przypadków:To może cię zranić, jeśli dodasz jakąś metodę przed powrotem. Wcięcie wskazuje, że powrót jest wykonywany, gdy warunek jest spełniony, ale zawsze będzie zwracany.
Inny przykład w C # z użyciem statment
co jest równoważne z
źródło
using
wyciągu i nie musisz :)using
).Najbardziej trafny przykład, jaki mogę wymyślić:
Z
if
czymelse
zostanie sparowany? Wcięcie oznacza, że zewnętrznyif
pobieraelse
, ale tak naprawdę kompilator tego nie zobaczy; wewnętrznyif
dostanieelse
, a zewnętrznaif
nie. Musisz wiedzieć, że (lub zobaczyć, jak zachowuje się w ten sposób w trybie debugowania), aby dowiedzieć się, sprawdzając, dlaczego ten kod może nie spełniać twoich oczekiwań. Staje się bardziej mylące, jeśli znasz Python; w takim przypadku wiesz, że wcięcie definiuje bloki kodu, więc można oczekiwać, że będzie ono obliczane zgodnie z wcięciem. C # nie daje jednak latającego przewrotu na temat białych znaków.To powiedziawszy, nie zgadzam się szczególnie z tą zasadą „zawsze używaj nawiasów” na jej twarzy. Powoduje to, że kod jest bardzo głośny w pionie, co zmniejsza jego zdolność do szybkiego czytania. Jeśli oświadczenie brzmi:
... to powinno być tak napisane. Stwierdzenie „zawsze używaj nawiasów” brzmi jak „zawsze otaczaj operacje matematyczne nawiasami”. To przekształciłoby bardzo proste stwierdzenie
a * b + c / d
w((a * b) + (c / d))
, wprowadzając możliwość pominięcia ścisłego paren (zmorę wielu koderów) i po co? Kolejność operacji jest dobrze znana i egzekwowana, dlatego nawiasy są zbędne. Używałbyś nawiasów tylko w celu wymuszenia innej kolejności operacji niż normalnie stosowane:a * (b+c) / d
na przykład. Blokowe nawiasy klamrowe są podobne; użyj ich, aby zdefiniować, co chcesz robić w przypadkach, w których różni się od domyślnego i nie jest „oczywisty” (subiektywny, ale zazwyczaj zdrowy rozsądek).źródło
else
z pierwszymif
zamiast drugiego. Proszę usunąć głosowanie negatywne.Przeglądając odpowiedzi, których nikt nie określił, jakiego rodzaju praktykę używam, opowiadając historię twojego kodu:
Staje się:
Kładzenie
j++
się na tej samej linii jak gdyby sygnał nikomu innemu, „Chcę tylko tego bloku kiedykolwiek przyrostuj
” . Z coursethis ma sens tylko wtedy, gdy linia jest tak proste, jak to możliwe, bo oddanie przerwania tutaj, jak peri wspomina, nie będzie bardzo przydatna.W rzeczywistości właśnie natknąłem się na część interfejsu API Twitter Storm, która zawiera ten „rodzaj” kodu w java, oto fragment relatywny z kodu wykonawczego, na stronie 43 tego pokazu slajdów :
Blok pętli for ma w sobie dwie rzeczy, więc nie wstawiłbym tego kodu. Tj. Nigdy :
To okropne i nawet nie wiem, czy to działa (zgodnie z przeznaczeniem); nie rób tego . Nowe linie i nawiasy klamrowe pomagają rozróżnić oddzielne, ale powiązane fragmenty kodu, w taki sam sposób, jak przecinek lub średnik w prozie. Powyższy blok jest równie kiepski, naprawdę długie zdanie z kilkoma klauzulami i kilkoma innymi stwierdzeniami, które nigdy nie łamią się ani nie przerywają, aby rozróżnić poszczególne części.
Jeśli naprawdę chcesz telegrafować do kogoś innego, jest to praca tylko w jednym wierszu, użyj operatora trójskładnikowego lub
?:
formularza:Ale to jest na granicy golfa kodowego i myślę, że nie jest to świetna praktyka (nie jest dla mnie jasne, czy powinienem umieścić j ++ po jednej stronie,
:
czy nie). NB: Nie korzystałem wcześniej z trójkowego operatora w C ++, nie wiem czy to działa, ale tak jest .W skrócie:
Wyobraź sobie, jak twój czytelnik (tj. Osoba obsługująca kod) interpretuje twoją historię (kod). Wyjaśnij im, jak to możliwe. Jeśli wiesz, że początkujący programista / uczeń utrzymuje to, być może nawet zostaw tak wiele,
{}
jak to możliwe, tylko po to, aby się nie pomylić.źródło
for
pętlę na jednej linii, dlaczego to nie powinno działać? Działa z tego samego powodu, dla którego można pominąć nawiasy klamrowe; nowa linia po prostu nie ma znaczenia w C ++. (3) Twój przykład operatora warunkowego, oprócz tego, że jest okropny, to niepoprawny C ++.Ponieważ bez dwóch stwierdzeń
{}
łatwo jest przeoczyć problem. Załóżmy, że kod wygląda tak.To wygląda dobrze. Problem z tym jest naprawdę łatwy do przeoczenia, szczególnie gdy funkcja zawierająca kod jest znacznie większa. Problem polega na tym, że
goto fail
jest prowadzony bezwarunkowo. Możesz łatwo wyobrazić sobie, jak to jest frustrujące (co powoduje, że pytasz, dlaczego ostatnihash_update
zawsze zawodzi, w końcu wszystkohash_update
działa dobrze ).Nie oznacza to jednak, że jestem za dodawaniem
{}
wszędzie (moim zdaniem widzenie{}
wszędzie jest denerwujące). Chociaż może powodować problemy, nigdy nie robił tego w przypadku moich własnych projektów, ponieważ mój osobisty styl kodowania zabrania warunkowych bez,{}
gdy nie są na tej samej linii (tak, zgadzam się, że mój styl kodowania jest niekonwencjonalny, ale podoba mi się i używaj stylu kodu projektu, gdy współtworzysz inne projekty). To sprawia, że następujący kod jest w porządku.Ale nie następna.
źródło
Sprawia, że kod jest bardziej czytelny, dzięki wyraźnemu zdefiniowaniu zakresu pętli i bloków warunkowych. Oszczędza to również przed przypadkowymi błędami.
źródło
wrt 6: Jest to bezpieczniejsze, ponieważ usunięcie wskaźnika zerowego nie jest możliwe. Jeśli przypadkowo przypadkowo przejdziesz tę ścieżkę dwa razy, nie spowoduje to, że uszkodzenie pamięci spowoduje zwolnienie pamięci, która jest wolna lub została przydzielona na coś innego.
Jest to większość problemu ze statycznymi obiektami zakresu plików i singletonami, które nie mają bardzo jasnego czasu życia i które zostały odtworzone po ich zniszczeniu.
W większości przypadków możesz tego uniknąć, używając auto_ptrs
źródło
NULL
po usunięciu. JeśliNULL
w takich okolicznościach wskaźnik ma prawidłową wartość, np. Wskaźnik wskazuje na buforowaną wartość iNULL
wskazuje niepoprawną pamięć podręczną. Ale gdy zobaczysz, że ktoś ustawia wskaźnik doNULL
ostatniej linii w destruktorze, zastanawiasz się, czy on zna C ++.)Podoba mi się zaakceptowana odpowiedź Luchiana, w rzeczywistości nauczyłem się na własnej skórze, że ma rację, więc zawsze używam nawiasów klamrowych, nawet dla bloków jednowierszowych. Jednak osobiście robię wyjątek, pisząc filtr, tak jak w twoim przykładzie. To:
wygląda na zagracony dla mnie. Oddziela pętlę for i instrukcję if na osobne akcje, podczas gdy tak naprawdę twoja intencja jest pojedynczą akcją: policzyć wszystkie liczby całkowite podzielne przez 2. W bardziej wyrazistym języku można to napisać w następujący sposób:
W językach, w których brakuje zamknięć, filtr nie może być wyrażony w pojedynczej instrukcji, ale musi być pętlą for, po której następuje instrukcja if. Jest to jednak jedno działanie w umyśle programisty i uważam, że powinno to zostać odzwierciedlone w kodzie, tak jak poniżej:
źródło
for (int i = 0; i < 100; i += 2);
, w celu kontynuowania sporu o wcięcie ;-) Prawdopodobnie moglibyśmy mieć całą oddzielną walkę, jak „najlepiej” wyrazić logikę „dla każdegoi
w pewnym zakresie z pewną właściwością” w C ++ bez pętli, używając koszmaru kombinacji standardowych algorytmówfilter_iterator
i / lubcounting_iterator
.i
z określonego zakresu z pewną właściwością”. Tyle, że zwykle w przypadku SO ludzie bardzo szybko ignorują aktualne pytanie na rzecz zupełnie innego podejścia do podanego przykładu. Ale wcięcie jest ważne , więc nie ;-)Jedną z opcji zapobiegania błędom opisanym powyżej jest podkreślenie tego, co chcesz się wydarzyć, gdy nie używasz nawiasów klamrowych. Znacznie trudniej jest nie zauważyć błędów podczas próby modyfikacji kodu.
źródło
else
nie jest powiązany zif
.Jeśli jesteś kompilatorem, nie robi to żadnej różnicy. Oba są takie same.
Ale dla programistów pierwszy jest bardziej przejrzysty, czytelny i mniej podatny na błędy.
źródło
{
Zresztą poza otwarciem na własnej linii.Kolejny przykład dodawania nawiasów klamrowych. Kiedyś szukałem błędu i znalazłem taki kod:
Jeśli czytasz metodę wiersz po wierszu, zauważysz, że w metodzie występuje warunek, który zwraca wartość, jeśli nie jest to prawda. Ale tak naprawdę wygląda to na 100 innych prostych procedur obsługi zdarzeń, które ustawiają niektóre zmienne na podstawie pewnych warunków. I pewnego dnia pojawia się Fast Coder i dodaje dodatkowe oświadczenie o zmiennej wartości na końcu metody:
W rezultacie SetAnotherVariableUnconditionnaly jest wykonywana, gdy SomeConditionIsMet (), ale szybki facet tego nie zauważył, ponieważ wszystkie linie mają prawie podobny rozmiar, a nawet gdy warunek powrotu jest wcięty pionowo, nie jest to tak zauważalne.
Jeśli warunkowy zwrot jest sformatowany w następujący sposób:
jest to zauważalne, a szybki koder znajdzie to na pierwszy rzut oka.
źródło
return
instrukcji w treści funkcji przed dodaniem czegoś do niej, nie należy pozwolić, aby szybki koder zbliżył się do kodu. Nie powstrzymasz takiego faceta od trollowania twojego kodu, włączając nawiasy klamrowe.Pierwszy uważam za jasny, a następnie drugi. Daje to wrażenie zamykania instrukcji, ponieważ mały kod jest w porządku, gdy kod staje się skomplikowany, bardzo
{...}
pomaga, nawet jeśli jestendif
lubbegin...end
źródło
Po zakończeniu najlepiej ustawić wskaźnik na NULL.
Oto przykład, dlaczego:
Klasa A wykonuje następujące czynności:
Klasa B wykonuje następujące czynności
W tym momencie zarówno klasa A, jak i klasa B mają wskaźniki wskazujące na ten sam blok pamięci, jeśli chodzi o klasę A, ten blok pamięci nie istnieje, ponieważ jest z nim zakończony.
Rozważ następujący problem:
Co jeśli wystąpił błąd logiczny w klasie A, który spowodował zapisanie go w pamięci, która teraz należy do klasy B?
W tym konkretnym przypadku nie wystąpi błąd wyjątku złego dostępu, ponieważ adres pamięci jest legalny, a klasa A skutecznie uszkadza dane klasy B.
Klasa B może ostatecznie upaść, jeśli napotka nieoczekiwane wartości, a kiedy się zawiesi, są szanse, że spędzisz dość dużo czasu na polowaniu na tego błędu w klasie B, gdy problem występuje w klasie A.
Jeśli ustawisz wskaźnik usuniętej pamięci na NULL, otrzymasz błąd wyjątku, gdy tylko jakiekolwiek błędy logiczne w klasie A spróbują zapisać do wskaźnika NULL.
Jeśli martwisz się błędem logicznym podwójnego usuwania, gdy wskaźniki po raz drugi mają wartość NULL, dodaj dla tego potwierdzenie.
Ponadto: jeśli zamierzasz obniżyć głosowanie, wyjaśnij to.
źródło
Zawsze posiadanie nawiasów klamrowych jest bardzo prostą i niezawodną zasadą. Jednak kod może wyglądać nieelegancko, gdy jest wiele nawiasów klamrowych. Jeśli reguły pozwalają pominąć nawiasy klamrowe, powinny istnieć bardziej szczegółowe reguły stylu i bardziej wyrafinowane narzędzia. W przeciwnym razie może łatwo powstać chaotyczny i mylący (nie elegancki) kod. Dlatego szukanie reguły pojedynczego stylu oddzielnie od pozostałych przewodników stylu i używanych narzędzi jest prawdopodobnie bezowocne. Przedstawię tylko kilka ważnych szczegółów dotyczących tej zasady nr 3, o których nawet nie wspomniano w innych odpowiedziach.
Pierwszym interesującym szczegółem jest to, że większość zwolenników tej zasady zgadza się na jej naruszenie w przypadku
else
. Innymi słowy, nie wymagają przeglądu takiego kodu:Zamiast tego, jeśli go zobaczą, mogą nawet zasugerować, aby napisać w ten sposób:
Jest to technicznie naruszenie tej zasady, ponieważ nie ma nawiasów klamrowych między
else
iif
. Taka dwoistość reguły ujawnia się, kiedy należy zastosować ją automatycznie do bazy kodu za pomocą bezmyślnego narzędzia. Rzeczywiście, po co się kłócić, po prostu pozwól narzędziu automatycznie zastosować styl.Drugi szczegół (który jest również często zapominany przez zwolenników tej reguły) jest taki, że błędy, które mogą się zdarzyć, nigdy nie są spowodowane jedynie naruszeniem tej zasady # 3. W rzeczywistości prawie zawsze wiążą się z naruszeniem reguły nr 1 (z którą nikt się nie kłóci). Ponownie, z punktu widzenia automatycznych narzędzi, nie jest trudno stworzyć narzędzie, które natychmiast narzeka, gdy naruszona zostanie reguła nr 1, dzięki czemu większość błędów można wychwycić na czas.
Trzecim szczegółem (często zapominanym przez przeciwników tej reguły) jest myląca natura pustego wyrażenia reprezentowanego przez pojedynczy średnik. Większość programistów z pewnym doświadczeniem prędzej czy później pomyliło się z powodu jednoznacznie umieszczonego średnika lub pustej instrukcji napisanej przy użyciu jedynego średnika. Dwa nawiasy klamrowe zamiast pojedynczego średnika są znacznie łatwiejsze do zauważenia.
źródło
Muszę przyznać, że nie zawsze używa się go
{}
na pojedynczej linii, ale to dobra praktyka.Powiedzmy, że piszesz kod bez nawiasów, który wygląda następująco:
for (int i = 0; i <100; ++ i) for (int j = 0; j <100; ++ j) DoSingleStuff ();
A po pewnym czasie chcesz dodać w
j
pętli inne rzeczy i po prostu to zrobić, wyrównując i zapomnieć o dodawaniu nawiasów.Przydział pamięci jest szybszy. Powiedzmy, że masz duży zakres i tworzysz duże tablice wewnątrz (bez,
new
więc są one w stosie). Te tablice usuwają się z pamięci tuż po opuszczeniu zakresu. Ale możliwe jest, że użyjesz tej tablicy w jednym miejscu i będzie ona przez pewien czas w stosie i będzie czymś w rodzaju śmieci. Ponieważ stos ma ograniczony i dość mały rozmiar, można go przekroczyć. Dlatego w niektórych przypadkach lepiej jest pisać,{}
aby temu zapobiec. UWAGA nie dotyczy pojedynczej linii, ale takich sytuacji:if (...) {// SomeStuff ... {// nie mamy, jeśli, podczas, itp. // SomeOtherStuff} // SomeMoreStuff}
Trzeci sposób użycia jest podobny do drugiego. To po prostu nie ma na celu uczynienia stosu czystszym, ale otwarcie niektórych funkcji. Jeśli używasz
mutex
długich funkcji, zwykle lepiej jest zablokować i odblokować tuż przed uzyskaniem dostępu do danych i zaraz po zakończeniu ich odczytu / zapisu. UWAGA ten sposób jest używany, jeśli masz własneclass
lubstruct
zconstructor
idestructor
do blokowania pamięci.Co więcej:
if (...) if (...) SomeStuff (); else SomeOtherStuff (); // przechodzi do drugiego jeśli, ale przydział pokazuje, że jest on pierwszy ...
Podsumowując, nie mogę powiedzieć, jaki jest najlepszy sposób, aby zawsze używać
{}
pojedynczej linii, ale nie jest to nic złego.WAŻNA EDYCJA Jeśli napiszesz nawiasy kompilujące kod dla pojedynczej linii, nic nie robi, ale jeśli twój kod zostanie zinterpretowany, bardzo nieznacznie spowalnia kod. Bardzo nieznacznie.
źródło
Istnieje wiele możliwych sposobów pisania instrukcji kontrolnych; niektóre ich kombinacje mogą współistnieć bez pogorszenia czytelności, ale inne kombinacje powodują problemy. Styl
będzie współistnieć wygodnie z niektórymi innymi sposobami pisania instrukcji kontrolnych, ale nie tak dobrze z innymi. Jeśli instrukcje sterowane wieloliniowo są zapisywane jako:
wtedy wizualnie będzie oczywiste, które
if
instrukcje kontrolują jedną linię, a które kontrolują wiele linii. Jeśli jednakif
wyrażenia wieloliniowe są zapisywane jako:wtedy prawdopodobieństwo, że ktoś spróbuje rozszerzyć konstrukcję pojedynczej instrukcji
if
bez dodania niezbędnych nawiasów klamrowych, może być znacznie wyższe.Instrukcja pojedynczego wyrażenia w następnym wierszu
if
może być również problematyczna, jeśli baza kodów w znacznym stopniu korzysta z formularzaOsobiście wolę, aby posiadanie instrukcji we własnej linii ogólnie poprawiało czytelność, z wyjątkiem przypadków, gdy istnieje wiele
if
instrukcji z podobnymi blokami kontrolnymi, np.w takim przypadku zwykle poprzedzam i podążam za takimi grupami
if
instrukcji pustą linią, aby wizualnie oddzielić je od innych kodów. Posiadanie szeregu stwierdzeń rozpoczynających sięif
od tego samego wcięcia zapewni wyraźne wizualne wskazanie, że istnieje coś niezwykłego.źródło