Jaki jest cel używania szelek (tj. {}) dla pojedynczej linii if lub loop?

Czytam notatki z wykładów mojego wykładowcy C++ i napisał:

  1. Użyj wcięcia / / OK
  2. nigdy nie polegaj na pierwszeństwie operatora - Zawsze używaj nawiasów / / OK
  3. Zawsze używaj {} bloku-nawet dla pojedynczej linii / / nie OK, Dlaczego ???
  4. Const obiekt po lewej stronie porównania // OK
  5. Użyj unsigned dla zmiennych, które są > = 0 / / nice trick
  6. ustaw wskaźnik NA NULL po usunięciu - Double delete protection / / not bad

Trzecia technika nie jest dla mnie jasna: co zyskam umieszczając jedną linię w a { ... }?

Na przykład, weźmy ten dziwny kod:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

I zastąp go:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;

Jakie są korzyści z używania pierwszej wersji?

Author: user2864740, 2012-08-30

23 answers

Spróbujmy również zmodyfikować i, gdy dodamy j:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
        i++;
O nie! Z Pythona wynika, że wygląda to dobrze, ale tak naprawdę nie jest, ponieważ jest odpowiednikiem:
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;

Oczywiście jest to głupi błąd, ale taki, który mógłby popełnić nawet doświadczony programista.

Kolejny bardzo dobry powód jest wskazany w ta.speot.is odpowiedź .

Trzeci , o którym myślę, to zagnieżdżone if ' s:

if (cond1)
   if (cond2) 
      doSomething();

Teraz, Załóżmy, że teraz chcę doSomethingElse(), Gdy cond1 nie jest spełnione(nowa funkcja). Więc:

if (cond1)
   if (cond2) 
      doSomething();
else
   doSomethingElse();

Co jest oczywiście błędne, ponieważ else kojarzy się z wewnętrznym if.


Edit: skoro to wzbudza trochę uwagi, wyjaśnię swój pogląd. Pytanie, na które odpowiadałem brzmi:

Jakie są korzyści z używania pierwszej wersji?

Które opisałem. Są pewne korzyści. Ale, IMO, zasady "zawsze" nie zawsze mają zastosowanie. Więc nie do końca popieram

Zawsze używaj {} bloku-nawet dla pojedynczej linii / / nie OK, dlaczego ???

Nie mówię zawsze używaj {} bloku. Jeśli jest to wystarczająco proste warunek & zachowanie, nie. jeśli podejrzewasz, że ktoś może przyjść później & zmienić kod, aby dodać funkcjonalność, zrobić.

 512
Author: Luchian Grigore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:19

Bardzo łatwo jest przypadkowo zmienić control-flow z komentarzami, jeśli nie używasz { i }. Na przykład:

if (condition)
  do_something();
else
  do_something_else();

must_always_do_this();

Jeśli skomentujesz do_something_else() jednym komentarzem liniowym, skończysz z tym:

if (condition)
  do_something();
else
  //do_something_else();

must_always_do_this();

Kompiluje, ale must_always_do_this() nie zawsze jest wywoływany.

Mieliśmy ten problem w naszej bazie kodu, gdzie ktoś wszedł, aby wyłączyć niektóre funkcje bardzo szybko przed wydaniem. Na szczęście złapaliśmy go w code review.

 330
Author: ta.speot.is,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 13:20:46

Mam wątpliwości co do kompetencji wykładowcy. Biorąc pod uwagę jego punkty:

  1. OK
  2. czy ktoś naprawdę napisze (lub chce przeczytać) (b*b) - ((4*a)*c)? Niektóre precedensy są oczywiste (lub powinny być), a dodatkowe nawiasy dodaj zamieszania. (Z drugiej strony, you _should_ use the nawiasy w mniej oczywistych przypadkach, nawet jeśli wiesz, że nie są potrzebne.)
  3. Tak jakby. Istnieją dwie szerokie konwencje formatowania warunki i pętle:
    if ( cond ) {
        code;
    }
    
    oraz:
    if ( cond )
    {
        code;
    }
    
    W pierwszym się z nim zgodzę. Otwarcie { nie jest tak widoczne, więc najlepiej założyć, że zawsze tam jest. W drugiej jednak (i większość osób, z którymi pracowałem) nie ma problemu z pominięciem szelki na jedno oświadczenie. (Pod warunkiem oczywiście, że wcięcia są systematyczne i konsekwentnie używasz tego stylu. (A wielu bardzo dobrych programistów, piszących bardzo czytelny kod, pomija szelki nawet przy formatowaniu pierwszego sposób.)
  4. Nie . Rzeczy takie jak {[4] } są na tyle brzydkie, że utrudniają czytelność. Napisz porównania intuicyjnie. (Które w wielu przypadkach powoduje stałą po prawej stronie.) Jego 4 to zła rada; cokolwiek co sprawia, że kod jest nienaturalny, czyni go mniej czytelnym.
  5. Nie . Wszystko poza int jest zarezerwowane dla szczególnych przypadków. Na doświadczonych programistów C i C++, wykorzystanie bitów sygnałów unsigned operatorzy. C++ nie ma prawdziwego typu kardynalnego (ani żadnego inne effective subrange type); unsigned nie działa dla wartości liczbowych, ze względu na zasady promocji. Wartości liczbowe, na których nie operacje arytmetyczne mają sens, podobnie jak numery seryjne, mogą prawdopodobnie być unsigned. Ja bym się jednak sprzeciwił, bo to wysyła błędną wiadomość: operacje bitowe też nie mają sensu. Podstawową zasadą jest, że typy całkowe to int, _unless_ istnieje istotny powód używania innego typu.
  6. Nie . Robiąc to systematycznie wprowadza w błąd, a właściwie nie chronić przed niczym. W ścisłym kodzie oo, {[10] } jest często najczęstszym przypadkiem (i nie można ustawić this na NULL), a w przeciwnym razie większość delete znajduje się w destruktorach, więc nie można uzyskać dostępu do pointer później tak czy siak. I ustawienie go na NULL nic nie da o innych wskaźnikach. Ustawianie wskaźnika systematycznie daje fałszywe poczucie bezpieczeństwa i nie naprawdę kupię ci cokolwiek.

Spójrz na kod w dowolnym z typowych odniesień. Stroustrup każda zasada, którą podałeś, z wyjątkiem pierwszej, na przykład.

Proponuję znaleźć innego wykładowcę. Kto wie co on mówi o.
 59
Author: James Kanze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-01 12:26:01

Wszystkie pozostałe odpowiedzi bronią Zasady 3 twojego wykładowcy.

Pozwolę sobie powiedzieć, ż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 się z tym problemem w prawdziwym życiu : wbrew temu, co sugerują inne odpowiedzi, ani razu nie zapomniałem dodać nawiasów klamrowych, gdy staną się konieczne. Jeśli użyjesz odpowiedniego wcięcia, stanie się od razu widać, że trzeba 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 i tak wymaga ogromnej troski.

Spójrzmy teraz na drugą stronę medalu: czy istnieje wada w używaniu nawiasów klamrowych? Pozostałe odpowiedzi po prostu ignorują ten punkt. Ale tam jest wadą: zajmuje dużo pionowego miejsca na ekranie, a to z kolei może sprawić, że Twój kod będzie nieczytelny, ponieważ oznacza to, że musisz przewijać więcej niż to konieczne.

Rozważ funkcję z wieloma klauzulami ochronnymi na początku (i tak, poniższy kod jest złym kodem C++, ale w innych językach byłaby to dość powszechna sytuacja):

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
    {
        throw null_ptr_error("a");
    }
    if (b == nullptr)
    {
        throw null_ptr_error("b");
    }
    if (a == b)
    {
        throw logic_error("Cannot do method on identical objects");
    }
    if (not a->precondition_met())
    {
        throw logic_error("Precondition for a not met");
    }

    a->do_something_with(b);
}

To jest okropny kod i zdecydowanie twierdzę, że poniżej jest znacznie bardziej czytelny:

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
        throw null_ptr_error("a");
    if (b == nullptr)
        throw null_ptr_error("b");
    if (a == b)
        throw logic_error("Cannot do method on identical objects");
    if (not a->precondition_met())
        throw logic_error("Precondition for a not met");

    a->do_something_with(b);
}

Podobnie, krótkie zagnieżdżone pętle korzystają z pominięcia nawiasów klamrowych:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
        for (auto j = 0; j < a.h(); ++j)
            c(i, j) = a(i, j) + b(i, j);

    return c;
}

Porównaj z:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
    {
        for (auto j = 0; j < a.h(); ++j)
        {
            c(i, j) = a(i, j) + b(i, j);
        }
    }

    return c;
}

Pierwszy kod jest zwięzły, drugi jest nadęty.

I tak, to może być złagodzone do pewnego stopnia {[10] } poprzez umieszczenie nawiasu otwierającego na poprzedniej linii. Ale to byłobynadal mniej czytelne niż kod bez nawiasów klamrowych.

W skrócie: nie pisz niepotrzebnego kodu, który zajmuje miejsce na ekranie.

 46
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-02 12:24:24

Baza kodowa, nad którą pracuję, jest rozrzucona po kodzie przez ludzi z patologiczną niechęcią do aparatów ortodontycznych, a dla ludzi, którzy przychodzą później, naprawdę może to zmienić konserwację.

Najczęstszym problematycznym przykładem, z jakim się spotkałem, jest to:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
    this_looks_like_a_then-statement_but_isn't;

Więc kiedy przychodzę i chcę dodać wtedy-oświadczenie, mogę łatwo skończyć z tym, jeśli nie jestem ostrożny:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
{
    this_looks_like_a_then-statement_but_isn't;
    i_want_this_to_be_a_then-statement_but_it's_not;
}

Biorąc pod uwagę, że potrzeba ~1sekundy, aby dodać aparat ortodontyczny i można zaoszczędzić co najmniej kilka debugowanie minut zdezorientowanych, dlaczego w ogóle nie wybrałeś opcję zmniejszonej wieloznaczności? Wydaje mi się, że to fałszywa Ekonomia.

 41
Author: jam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 10:27:51

Moje 2C:

Użyj Wcięcia

Oczywiście

Nigdy nie polegaj na pierwszeństwie operatora - Zawsze używaj nawiasów

Nie użyłbym słów "nigdy i "zawsze", ale ogólnie widzę, że ta zasada jest przydatna. W niektórych językach (Lisp, Smalltalk) nie jest to problem.

Zawsze używaj bloku {} - nawet dla pojedynczej linii

Nigdy tego nie robiłem i nigdy nie miałem żadnego problemu, ale widzę, jak to może być dobre dla uczniów, esp. jeśli wcześniej uczyli się Pythona.

Const obiekt po lewej stronie porównania

Warunki Yody? Nie, proszę. To szkodzi czytelności. Po prostu użyj maksymalnego poziomu ostrzeżenia podczas kompilacji kodu.

Użyj unsigned dla zmiennych, które są >= 0

OK. Zabawne, Słyszałem, że Stroustrup się nie zgadza.

Ustaw wskaźnik NA NULL po usunięciu-podwójne zabezpieczenie przed usunięciem

Zła rada! Nigdy nie miej wskaźnika, który wskazuje do usuniętego lub nieistniejącego obiektu.

 20
Author: Nemanja Trifunovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 12:19:46

Jest bardziej intuicyjny i zrozumiały. To wyjaśnia intencje.

I zapewnia, że kod nie pęknie, gdy nowy użytkownik może nieświadomie przegapić {, } Podczas dodawania nowej instrukcji code.

 19
Author: Alok Save,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 08:52:24

Aby dodać do bardzo sensownych sugestii powyżej, jeden przykład, który napotkałem podczas refaktoryzacji kodu, w którym staje się to krytyczne, był następujący: zmieniałem bardzo dużą bazę kodową, aby przejść z jednego API do drugiego. Pierwsze API miało wywołanie, aby ustawić ID firmy w następujący sposób:

setCompIds( const std::string& compId, const std::string& compSubId );

Podczas gdy wymiana wymagała dwóch wywołań:

setCompId( const std::string& compId );
setCompSubId( const std::string& compSubId );

Postanowiłem zmienić to za pomocą wyrażeń regularnych, co było bardzo udane. Przekazaliśmy również kod przez astyle, który naprawdę sprawił, że był o wiele bardziej czytelny. Następnie, część procesu przeglądu, odkryłem, że w pewnych okolicznościach warunkowych to zmienia:

if ( condition )
   setCompIds( compId, compSubId );

Do tego:

if ( condition )
   setCompId( compId );
setCompSubId( compSubId );

Co wyraźnie nie jest tym, co było wymagane. Musiałem wrócić do początku zrobić 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 wyglądzie głupkowatym (przynajmniej nie byłoby to nieprawidłowe.)

Zauważyłem, że astyle ma teraz opcję --add-brackets, która pozwala na dodawanie nawiasów tam, gdzie ich nie ma i zdecydowanie polecam, jeśli kiedykolwiek znajdziesz się w tej samej pozycji, co ja.

 14
Author: Component 10,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 10:30:41

Używam

Wszędzie, z wyjątkiem kilku przypadków, w których jest to oczywiste. Pojedyncza linia jest jednym z przypadków:

if(condition) return; // OK

if(condition) // 
   return;    // and this is not a one-liner 

Może cię to zranić, gdy dodasz jakąś metodę przed powrotem. Wcięcie wskazuje, że return jest wykonywany, gdy warunek jest spełniony, ale zawsze będzie zwracany.

Inny przykład w C# z użyciem statment

using (D d = new D())  // OK
using (C c = new C(d))
{
    c.UseLimitedResource();
}

Co jest równoważne

using (D d = new D())
{
    using (C c = new C(d))
    {
        c.UseLimitedResource();
    }
}
 8
Author: Lukasz Madon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-08 13:29:53

Najbardziej trafny przykład, jaki przychodzi mi do głowy:

if(someCondition)
   if(someOtherCondition)
      DoSomething();
else
   DoSomethingElse();

Z którym if będzie sparowany else? Wcięcie sugeruje, że zewnętrzny if otrzymuje else, ale tak naprawdę kompilator nie będzie go widział; wewnętrzny if będziesz musiał to wiedzieć (lub zobaczyć, jak zachowuje się w ten sposób w trybie debugowania), aby dowiedzieć się przez Inspekcję, dlaczego ten kod może nie spełniać Twoich oczekiwań. Robi się bardziej mylące, jeśli znasz Pythona; w takim przypadku wiesz, że wcięcie definiuje bloki kodu, więc spodziewasz się, że będzie ono oceniane zgodnie z wcięciem. C# ma jednak w nosie białe znaki.

To powiedziawszy, nie zgadzam się szczególnie z tą zasadą "Zawsze używaj nawiasów" na jego twarzy. Sprawia, że kod jest bardzo głośny pionowo, zmniejszając możliwość szybkiego odczytu. Jeśli twierdzenie jest:

if(someCondition)
   DoSomething();

... więc powinno być napisane w ten sposób. Stwierdzenie " Zawsze używaj nawiasów" brzmi jak "zawsze otaczaj operacje matematyczne nawiasami". To zmieniłoby bardzo proste stwierdzenie a * b + c / d w ((a * b) + (c / d)), wprowadzając możliwość pominięcia close-paren (zmory wielu programistów), i po co? Kolejność operacji jest dobrze znana i egzekwowana, więc nawiasy są zbędne. Używasz nawiasów tylko do wymuszania innej kolejności operacji niż normalnie stosowana: a * (b+c) / d na przykład. Szelki blokowe są podobne; użyj ich, aby określić, co Ty chcesz zrobić w przypadkach, gdy różni się od domyślnego, i nie jest " oczywiste "(subiektywne, ale zazwyczaj dość zdroworozsądkowe).

 8
Author: KeithS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-13 00:17:12

Ponieważ kiedy masz dwa stwierdzenia Bez {}, łatwo jest pominąć problem. Załóżmy, że kod wygląda tak.

int error = 0;
enum hash_type hash = SHA256;
struct hash_value *hash_result = hash_allocate();

if ((err = prepare_hash(hash, &hash_result))) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &client_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &server_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &exchange_params)) != 0)
    goto fail;
    goto fail;
if ((err = hash_finish(hash)) != 0)
    goto fail;

error = do_important_stuff_with(hash);

fail:
hash_free(hash);
return error;
Wygląda dobrze. Problem z nim jest naprawdę łatwy do pominięcia, zwłaszcza gdy funkcja zawierająca kod jest znacznie większa. Problem polega na tym, że goto fail jest uruchamiany bezwarunkowo. Łatwo możesz sobie wyobrazić, jakie to frustrujące (zmuszając do pytania, dlaczego last hash_update zawsze zawodzi, w końcu wszystko wygląda dobrze w funkcji hash_update).

Jednak, że nie znaczy to, że jestem za dodawaniem {} wszędzie (moim zdaniem widzenie {} wszędzie jest denerwujące). Chociaż może to powodować problemy, nigdy nie miało to Miejsca dla moich własnych projektów, ponieważ mój osobisty styl kodowania zabrania Warunkom bez {}, gdy nie są one na tej samej linii (tak, Zgadzam się, że mój styl kodowania jest niekonwencjonalny, ale podoba mi się i używam stylu kodu projektu, gdy przyczyniam się do innych projektów). To sprawia, że poniższy kod jest w porządku.

if (something) goto fail;

Ale nie następny.

if (something)
    goto fail;
 5
Author: Konrad Borowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-25 18:58:37

Sprawia, że kod jest bardziej czytelny poprzez wyraźne zdefiniowanie zakresu pętli i bloków warunkowych. Chroni również przed przypadkowymi błędami.

 4
Author: Drona,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 08:54:23

Wrt 6: jest to bezpieczniejsze, ponieważ usuwanie wskaźnika null jest no-op. więc jeśli przypadkowo przejdziesz przez tę ścieżkę dwa razy, nie spowodujesz uszkodzenia pamięci, która uwolni pamięć, która jest albo wolna, albo została przydzielona do czegoś innego.

Jest to większość problemów ze statycznymi obiektami zakresu plików i singletonami, które nie mają zbyt jasnego okresu życia i są znane z odtwarzania po ich zniszczeniu.

W większości przypadków można tego uniknąć, używając auto_ptrs

 4
Author: Tom Tanner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 09:30:56

Podoba mi się przyjęta odpowiedź Luchiana, w rzeczywistości nauczyłem się na własnej skórze, że ma rację, więc zawsze używam szelek, nawet do bloków jednoliniowych. Jednak osobiście robię wyjątek przy pisaniu filtra, jak jesteś w swoim przykładzie. To:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}
Dla mnie wygląda na zagmatwaną. Oddziela pętlę for I instrukcję if na osobne akcje, gdy tak naprawdę intencja jest pojedynczą akcją: policzyć wszystkie liczby całkowite podzielne przez 2. W bardziej wyrazistym języku można by to napisać coś w stylu:
j = [1..100].filter(_%2 == 0).Count

W językach, w których nie ma zamknięć, filtr nie może być wyrażony w pojedynczej instrukcji, ale musi być pętlą for, po której następuje Instrukcja if. Jednak nadal jest to jedno działanie w umyśle programisty i uważam, że powinno to znaleźć odzwierciedlenie w kodzie, w ten sposób: {]}

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
  if (i % 2 == 0)
{
    j++;
}
 4
Author: MikeFHay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 13:05:05

Jedną z opcji pomagających zapobiec opisanym powyżej błędom jest wpisanie tego, co chcesz się wydarzyć, gdy nie używasz aparatu ortodontycznego. Znacznie trudniej jest nie zauważyć błędów podczas próby modyfikacji kodu.

if (condition) doSomething();
else doSomethingElse();

if (condition) doSomething();
    doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong
 4
Author: Blacktiger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 15:08:17

Przeglądając odpowiedzi nikt nie powiedział wprost, jakiego rodzaju praktykę robię w zwyczaju, opowiadając historię Twojego kodu:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

Staje się:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0) j++;
}

Umieszczenie {[5] } na tej samej linii , co if powinno sygnalizować komukolwiek innemu, "chcę tylko, aby ten blok kiedykolwiek się zwiększał j". Oczywiście jest to opłacalne tylko wtedy, gdy linia jest tak uproszczona, jak to tylko możliwe, ponieważ umieszczenie tutaj punktu przerwania, jak wspomina peri, Nie będzie zbyt przydatne.

W rzeczywistości właśnie natknąłem się na Część API Twitter Storm, która ma taki "sortowanie" kodu w Javie, oto relvantowy fragment kodu execute, na stronie 43 tego pokazu slajdów :
...
Integer Count = counts.get(word);
if (Count=null) count=0;
count++
...

Blok pętli for ma w sobie dwie rzeczy, więc nie wpisywałbym tego kodu. I. E nigdy:

int j = 0;
for (int i = 0 ; i < 100 ; ++i) if (i % 2 == 0) j++;

To jest straszne i nawet nie wiem, czy to działa (zgodnie z przeznaczeniem); nie rób tego . Nowe linie i szelki pomagają odróżnić oddzielne, ale powiązane elementy kod, tak samo jak przecinek lub średnik w prozie. Powyższy blok jest tak źle, że naprawdę długie zdanie z kilkoma klauzulami i kilkoma innymi stwierdzeniami, które nigdy nie pękają lub nie zatrzymują się w celu rozróżnienia oddzielnych części.

Jeśli naprawdę chcesz telegraf do kogoś innego jest to praca tylko jednolinijkowa użyj operatora trójlinijkowego lub ?: forma:

for (int i = 0 ; i < 100 ; ++i) (i%2 ? 0 : >0) j++;

Ale to jest na granicy code-golfa, i myślę, że nie jest to świetna praktyka (nie jest dla mnie jasne, czy powinienem umieścić j++ na jednej stronie : lub nie). NB nie uruchamiałem wcześniej operatora trójdzielnego w C++, Nie wiem czy to działa, ale istnieje.

W skrócie:

Wyobraź sobie, jak Twój czytelnik (tj. osoba pisząca kod) interpretuje Twoją historię (kod). Wyjaśnij im to tak jasno, jak to tylko możliwe. Jeśli wiesz, że początkujący programista / student utrzymuje to, być może zostaw tak wiele {}, Jak to możliwe, tylko po to, aby się nie pomylić.

 4
Author: Pureferret,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Jeśli jesteś kompilatorem, to nie robi to żadnej różnicy. Oba są takie same.

Ale dla programistów pierwszy z nich jest bardziej przejrzysty, czytelny i mniej podatny na błędy.

 3
Author: P.P,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 08:55:13

Kolejny przykład dodawania nawiasów klamrowych. Kiedyś Szukałem błędu i znalazłem taki kod:

void SomeSimpleEventHandler()
{
    SomeStatementAtTheBeginningNumber1;
    if (conditionX) SomeRegularStatement;
    SomeStatementAtTheBeginningNumber2;
    SomeStatementAtTheBeginningNumber3;
    if (!SomeConditionIsMet()) return;
    OtherwiseSomeAdditionalStatement1;
    OtherwiseSomeAdditionalStatement2;
    OtherwiseSomeAdditionalStatement3;
}

Jeśli odczytasz metodę linia po linii, zauważysz, że w metodzie istnieje warunek, który zwraca, jeśli nie jest to prawda. Ale w rzeczywistości wygląda to jak 100 innych prostych procedur obsługi zdarzeń, które ustawiają pewne zmienne w oparciu o pewne warunki. I pewnego dnia przychodzi szybki koder i dodaje dodatkową instrukcję ustawiania zmiennej na końcu metody:

{
    ...
    OtherwiseSomeAdditionalStatement3;
    SetAnotherVariableUnconditionnaly;
}

W wyniku SetAnotherVariableUnconditionnaly jest wykonywane, gdy someconditionismet (), ale fast guy nie zauważył tego, ponieważ wszystkie linie są prawie podobne pod względem wielkości i nawet gdy warunek powrotu jest wcięty pionowo, nie jest tak zauważalny.

Jeśli zwrot warunkowy jest sformatowany w następujący sposób:

if (!SomeConditionIsMet())
{
    return;
}

Jest to znacznie zauważalne i szybki koder znajdzie to na pierwszy rzut oka.

 3
Author: Artemix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-05 07:24:55

Uważam, że pierwszy jest jasny, a drugi. Daje poczucie zamknięcia instrukcji, z małym kodem jest w porządku, gdy kod staje się złożony {...} bardzo pomaga, nawet jeśli jest to endif lub begin...end

//first
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}


//second
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;
 2
Author: RollRoll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-28 21:06:41

Najlepiej jest ustawić wskaźnik NA NULL po jego zakończeniu.

Oto przykład dlaczego:

Klasa A wykonuje następujące czynności:

  1. przydziela blok pamięci
  2. jakiś czas później usuwa ten blok pamięci, ale nie ustawia wskaźnika na NULL

Klasa B wykonuje następujące czynności

  1. przydziela pamięć (i w tym przypadku zdarza się, że otrzymuje ten sam blok pamięci, który został usunięty przez klasę A.)

W tym punkt 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 nim zakończony.

Rozważ następujący problem:

Co jeśli w klasie A wystąpił błąd logiczny, który skutkował zapisem do pamięci, która teraz należy do klasy B?

W tym konkretnym przypadku, nie otrzymasz błędu bad access exception, ponieważ adres pamięci jest legalny, przez cały czas Klasa A jest teraz skutecznie uszkadza dane klasy B.

Klasa B może w końcu ulec awarii, jeśli napotka nieoczekiwane wartości, a gdy dojdzie do awarii, jest szansa, że spędzisz sporo czasu na polowaniu na ten błąd w klasie B, gdy problem jest w klasie A.

Jeśli Ustawiłeś wskaźnik usuniętej pamięci NA NULL, otrzymałbyś błąd wyjątku, gdy tylko jakiekolwiek błędy logiczne w klasie A próbowały napisać do wskaźnika NULL.

Jeśli obawiasz się błędu logicznego z double delete, gdy wskaźniki są NULL po raz drugi, a następnie dodaj assert dla tego.

Również: jeśli zamierzasz odrzucić głosowanie, proszę o wyjaśnienie.

 1
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-02 21:44:25

Zawsze posiadanie kręconych aparatów ortodontycznych jest bardzo prostą i solidną zasadą. Jednak kod może wyglądać nieeleganckie, gdy jest dużo aparatów ortodontycznych. Jeśli reguły pozwalają na pominięcie nawiasów klamrowych, powinny istnieć bardziej szczegółowe zasady stylu i bardziej wyrafinowane narzędzia. W przeciwnym razie może to łatwo wynikać z chaotycznego i mylącego (nie eleganckiego) kodu. Dlatego szukanie reguły pojedynczego stylu oddzielnie od pozostałych użytych przewodników stylów i narzędzi jest prawdopodobnie bezowocne. Przedstawię tylko kilka ważnych szczegółów na temat tej zasady #3, która nawet nie wspomniano w innych odpowiedziach.

Pierwszy interesujący szczegół jest taki, że większość zwolenników tej zasady zgadza się ją naruszyć w przypadku else. Innymi słowy, nie wymagają w przeglądzie takiego kodu:

// pedantic rule #3
if ( command == Eat )
{
    eat();
}
else
{
    if ( command == Sleep )
    {
        sleep();
    }
    else
    {
        if ( command == Drink )
        {
            drink();
        }
        else
        {
            complain_about_unknown_command();
        }
    }
}

Zamiast tego, jeśli to zobaczą, mogą nawet zasugerować napisanie tego w ten sposób:

// not fully conforming to rule #3
if ( command == Eat )
{
    eat();
}
else if ( command == Sleep )
{
    sleep();
}
else if ( command == Drink )
{
    drink();
}
else
{
   complain_about_unknown_command();
}

Jest to technicznie naruszenie tej zasady, ponieważ między else a if nie ma nawiasów klamrowych. Taka dualność powierzchni reguły, gdy próbuje się ją zastosować do bazy kodu automatycznie 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 zasady) jest taki, że błędy, które mogą się zdarzyć, nigdy nie są tylko z powodu naruszenia tej zasady #3. Właściwie te prawie zawsze wiążą się z naruszeniem zasady #1 zbyt (że nikt nie kłóci się z). Ponownie z punktu widzenia automatycznych narzędzi, nie jest trudno zrobić narzędzie, które natychmiast skarży się, gdy reguła #1 jest naruszona i tak większość błędów można złapać na czas.

Trzeci szczegół (często zapominany przez przeciwników tej reguły) to myląca natura pustego wyrażenia reprezentowanego przez pojedynczy średnik. Większość programistów z pewnym doświadczeniem prędzej czy później została zdezorientowana przez sole błędnie umieszczony średnik lub przez puste polecenie, które jest napisane za pomocą sole średnik. Dwa kręcone szelki zamiast pojedynczego średnika są wizualnie łatwiejsze do zauważenia.

 1
Author: Öö Tiib,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-30 12:04:04

Muszę przyznać, że nie zawsze używaj {} do pojedynczej linii, ale to dobra praktyka.

  • Powiedzmy, że piszesz kod bez nawiasów, który wygląda tak:

    For (int i = 0; i

I po jakimś czasie chcesz dodać w j inne rzeczy i robisz to wyrównując i zapominasz dodać nawiasy.

  • Dealokacja pamięci jest szybsza. Powiedzmy masz duży zakres i tworzysz duże tablice wewnątrz (Bez new, więc są one w stosie). Tablice usuwają się z pamięci zaraz po opuszczeniu scope. Ale jest możliwe, że użyjesz tej tablicy w jednym miejscu i będzie ona przez jakiś czas w stosie i będzie jakimś śmieciem. Ponieważ stos ma ograniczony i dość mały rozmiar, możliwe jest przekroczenie rozmiaru stosu. Więc w niektórych przypadkach lepiej jest napisać {}, aby temu zapobiec. uwaga to nie jest dla pojedynczej linii, ale dla takiej sytuacje:

    If (...) { // SomeStuff... {//nie mamy if, while, etc. // SomeOtherStuff } // SomeMoreStuff }

  • Trzeci sposób użycia jest podobny do drugiego. Po prostu nie po to, aby uczynić stack cleaner, ale aby otworzyć niektóre funkcje. Jeśli używasz mutex w długich funkcjach, zwykle lepiej jest zablokować i odblokować tuż przed dostępem do danych i tuż po zakończeniu odczytu/zapisu. uwaga ten sposób jest używany, jeśli masz jakieś własne class lub struct z constructor i destructor aby zablokować pamięć.

  • Co więcej:

    If (...) if (...) SomeStuff(); else SomeOtherStuff (); / / idzie do drugiego if, ale pokazuje, że jest na pierwszym...

W sumie, nie mogę powiedzieć, jaki jest najlepszy sposób, aby zawsze używać {} dla pojedynczej linii, ale to nie jest nic złego, aby to zrobić.

Ważna edycja jeśli piszesz kompilowanie nawiasów kodu dla pojedynczej linii nic nie robi, ale jeśli Twój kod zostanie zinterpretowany to spowalnia kod na bardzo bardzo lekko. Bardzo lekko.

 1
Author: ST3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-30 15:14:51

Istnieje wiele możliwych sposobów pisania instrukcji sterowania; niektóre ich kombinacje mogą współistnieć bez pogorszenia czytelności, ale inne kombinacje mogą powodować kłopoty. Styl

if (condition)
  statement;

Będzie współistnieć wygodnie z niektórymi innymi sposobami pisania instrukcji kontrolnych, ale nie tak dobrze z innymi. If multi-line controlled statements are written as:

if (condition)
{
  statement;
  statement;
}

Wtedy będzie wizualnie oczywiste, które if instrukcje sterują pojedynczą linią, a które one kontrolują wiele linii. Jeśli jednak Wielowierszowe if wyrażenia zapisywane są jako:

if (condition) {
  statement;
  statement;
}

Wtedy prawdopodobieństwo, że ktoś spróbuje rozszerzyć konstrukcje jednotematyczne if bez dodawania niezbędnych szelek może być znacznie większe.

Wyrażenie single-statement-on-next line if może być również problematyczne, jeśli baza kodowa znacznie wykorzystuje formularz

if (condition) statement;

Moje własne preferencje są takie, że posiadanie oświadczenia na własnej linii ogólnie zwiększa czytelność z wyjątkiem przypadków, gdy istnieje wiele if instrukcji z podobnymi blokami sterowania, np.

if (x1 > xmax) x1 = xmax;
if (x1 < xmin) x1 = xmin;
if (x2 > xmax) x2 = xmax;
if (x2 < xmin) x2 = xmin;
etc.

W takim przypadku zwykle poprzedzam i podążam za takimi grupami if poleceń pustą linią, aby wizualnie oddzielić je od innych kodów. Mając szereg wyrażeń zaczynających się od if w tym samym wcięciu, uzyskamy wyraźną wizualną sygnalizację, że jest coś niezwykłego.

 1
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-16 21:16:22