Какова цель использования фигурных скобок (т.е. {}) Для однострочного if или цикла?

Я читаю лекции моего лектора C++, и он написал следующее:

  • Использовать отступы //OK
  • Никогда не полагайтесь на приоритет оператора - всегда используйте круглые скобки //OK
  • Всегда используйте блок {} - даже для одной строки // не ОК, почему???
  • Объект Const с левой стороны сравнения //OK
  • Используйте unsigned для переменных, которые >= 0//nice trick
  • Установить указатель на NULL после удаления - Двойная защита удаления//Неплохо

Третья техника мне не понятна: что бы я выиграл, поставив одну строку в a { ... }?

Например, возьмите этот странный код:

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

и замените его на:

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

Какая польза от использования 1-й версии?

Ответ 1

Попробуйте также изменить i, когда мы увеличиваем j:

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

О нет! Исходя из Python, это выглядит нормально, но на самом деле это не так, как это эквивалентно:

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

Конечно, это глупая ошибка, но это может сделать даже опытный программист.

Еще одна очень хорошая причина указана в ответе ta.speot.is.

Третий, о котором я могу думать, является вложенным if:

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

Теперь предположим, что теперь вы хотите doSomethingElse(), когда cond1 не выполняется (новая функция). Итак:

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

что, очевидно, неверно, так как else связывается с внутренним if.


Изменить: Поскольку это получает некоторое внимание, я уточню свое мнение. Вопрос, на который я отвечал:

Какая польза от использования 1-й версии?

Что я описал. Есть некоторые преимущества. Но правила ИМО "всегда" не всегда применяются. Поэтому я не полностью поддерживаю

Всегда используйте блок {} - даже для одной строки//не в порядке, почему???

Я не говорю, что всегда используйте блок {}. Если это достаточно простое условие и поведение, не делайте этого. Если вы подозреваете, что кто-то может прийти позже и изменить свой код, чтобы добавить функциональность, сделайте.

Ответ 2

Очень легко случайно изменить поток управления с комментариями, если вы не используете { и }. Например:

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

must_always_do_this();

Если вы прокомментируете do_something_else() одним комментарием, вы получите следующее:

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

must_always_do_this();

Он компилируется, но must_always_do_this() не всегда вызывается.

У нас была эта проблема в нашей базе кода, где кто-то вошел, чтобы отключить некоторые функции очень быстро перед выпуском. К счастью, мы поймали его в обзоре кода.

Ответ 3

У меня есть сомнения относительно компетенции лектора. Учитывая его указывает:

  • OK
  • Кто-нибудь действительно напишет (или хочет прочитать) (b*b) - ((4*a)*c)? Некоторые приоритеты очевидны (или должны быть), а дополнительные скобки просто добавьте в замешательство. (С другой стороны, вы должны использовать скобки в менее очевидных случаях, даже если вы знаете, что они не необходимо).
  • Сортировка. Существует два широко распространенных соглашения для форматирования условные и циклы:
    if ( cond ) {
        code;
    }
    
    а также:
    if ( cond )
    {
        code;
    }
    
    Во-первых, я согласен с ним. Открытие { не так заметно, поэтому лучше всего предположить, что он всегда там. Во втором, однако, я (и большинство людей, с которыми я работал) не имеют проблем с отсутствием скобки для одного утверждения. (При условии, конечно, что отступы систематичны и вы последовательно используете этот стиль. (И много очень хороших программистов, пишущих очень читаемый код, опускать скобки даже при форматировании первого пути.)
  • НЕТ. Такие вещи, как if ( NULL == ptr ), достаточно уродливы, чтобы помешать читаемость. Пишите сравнения интуитивно. (Что во многих случаях приводит к константе справа.) Его 4 - плохой совет; что-нибудь что делает код неестественным, делает его менее читаемым.
  • НЕТ. Все, кроме int зарезервировано для особых случаев. к опытные программисты на C и С++, использование бит unsigned сигналов операторы. С++ не имеет реального кардинального типа (или любого другого эффективный тип поддиапазона); unsigned не работает для числовых значений, из-за правил продвижения. Числовые значения, на которых нет арифметические операции имели бы смысл, как и серийные номера, могли бы предположительно, unsigned. Я бы возражал против этого, потому что это отправляет неправильное сообщение: побитовые операции также не имеют смысла. Основное правило состоит в том, что интегральные типы int, _unless_ есть существенная причина использования другого типа.
  • НЕТ. Выполнение этого систематически вводит в заблуждение и на самом деле защищать от чего-либо. В строгом коде OO delete this; часто наиболее частый случай (и вы не можете установить this в NULL), и в противном случае большинство delete находятся в деструкторах, поэтому вы не можете получить доступ к указатель позже в любом случае. И установка его на NULL ничего не делает о любых других указателях, плавающих вокруг. Установка указателя систематически до NULL дает ложное чувство безопасности и не действительно купите вам что угодно.

Посмотрите на код в любой из типичных ссылок. Строуструп нарушает каждое правило, которое вы указали, за исключением, например, первого.

Я предлагаю вам найти другого лектора. Тот, кто действительно знает, что он говорит.

Ответ 4

Все остальные ответы защищают правило ваших лекторов 3.

Позвольте мне сказать, что я согласен с вами: правило избыточно, и я бы не советовал ему. Это правда, что он теоретически предотвращает ошибки, если вы всегда добавляете фигурные скобки. С другой стороны, Ive никогда не сталкивался с этой проблемой в реальной жизни: вопреки тому, что подразумевают другие ответы, я ни разу не забыл добавить фигурные скобки, когда они стали необходимыми. Если вы используете правильный отступ, сразу становится очевидным, что вам нужно добавить фигурные скобки еще раз, чем один отступ.

Ответ на "Компонент 10" на самом деле выделяет единственный возможный случай, когда это может привести к ошибке. Но, с другой стороны, замена кода через регулярное выражение всегда гарантирует огромную осторожность.

Теперь посмотрим на другую сторону медали: есть ли недостаток в том, чтобы всегда использовать фигурные скобки? Другие ответы просто игнорируют этот момент. Но есть недостаток: он занимает много вертикального пространства экрана, а это, в свою очередь, может сделать ваш код нечитаемым, потому что это означает, что вам нужно прокручивать больше, чем необходимо.

Рассмотрим функцию с множеством защитных предложений в начале (и да, следующий код плохой С++, но на других языках это будет довольно распространенная ситуация):

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);
}

Это ужасный код, и я категорически утверждаю, что следующее более читаемо:

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);
}

Аналогично, короткие вложенные петли выигрывают от опускания фигурных скобок:

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;
}

Сравните с:

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;
}

Первый код является кратким; второй код раздувается.

И да, это может быть смягчено до некоторой степени, положив открытую фигуру на предыдущую строку. Но это все равно будет менее читаемым, чем код без каких-либо фигурных скобок.

Вкратце: не записывайте ненужный код, который занимает пространство экрана.

Ответ 5

Кодовая база, над которой я работаю, разбросана по коду людьми с патологическим отвращением к фигурным скобкам, а для людей, которые приходят позже, действительно может иметь значение для ремонтопригодности.

Наиболее частым проблемным примером, с которым я столкнулся, является следующее:

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;

Итак, когда я прихожу и хочу добавить then-statement, я могу легко закончить с этим, если я не буду осторожен:

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;
}

Учитывая, что для добавления фигурных скобок требуется ~ 1 секунда, и вы можете сэкономить как минимум несколько пустых минут для отладки, почему бы вам не пойти с вариантом уменьшенной двусмысленности? Для меня это кажется ложным.

Ответ 6

My 2c:

Использование отступов

Очевидно,

Никогда не полагайтесь на приоритет оператора - всегда используйте круглые скобки

Я бы не использовал слова "никогда" и "всегда", но в целом я вижу, что это правило полезно. На некоторых языках (Lisp, Smalltalk) это не проблема.

Всегда используйте блок {} - даже для отдельной строки

Я никогда этого не делал и никогда не имел ни одной проблемы, но я вижу, как это может быть хорошо для студентов, особенно. если они раньше изучали Python.

Объект Const с левой стороны сравнения

Условия йоды? Нет пожалуйста. Это больно читаемости. Просто используйте максимальный уровень предупреждения при компиляции кода.

Используйте unsigned для переменных, которые >= 0

OK. Забавно, я слышал, что Страуструп не согласен.

Установить указатель на NULL после удаления - Защита двойного удаления

Плохой совет! Никогда не указывайте указатель на удаленный или несуществующий объект.

Ответ 7

он более интуитивно понятен и легко понятен. Это делает цель понятной.

И это гарантирует, что код не сломается, когда новый пользователь может неосознанно пропустить {, } при добавлении нового оператора кода.

Ответ 8

Чтобы добавить к очень разумным предложениям, приведенным выше, один из примеров, с которыми я столкнулся при рефакторинге некоторого кода, где это становится критическим, был следующим: я изменял очень большую базу кода, чтобы переключиться с одного API на другой. В первом API было предложено установить идентификатор компании следующим образом:

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

тогда как для замены необходимы два вызова:

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

Я решил изменить это, используя регулярные выражения, которые были очень успешными. Мы также передали код через astyle, что действительно сделало его более читаемым. Затем, частично через процесс обзора, я обнаружил, что в некоторых условных обстоятельствах он менял это:

if ( condition )
   setCompIds( compId, compSubId );

Для этого:

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

что явно не является тем, что требовалось. Я должен был вернуться к началу, сделав это снова, рассмотрев замену как полностью внутри блока, а затем вручную изменив все, что в итоге выглядело тупо (по крайней мере, это было бы неверно.)

Я заметил, что astyle теперь имеет опцию --add-brackets, которая позволяет добавлять скобки, где их нет, и я настоятельно рекомендую это, если вы когда-нибудь окажетесь в том же положении, что и я.

Ответ 9

Я использую {} всюду, за исключением нескольких случаев, когда это очевидно. Одна строка - один из следующих случаев:

if(condition) return; // OK

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

Это может повредить вам, когда вы добавите какой-либо метод перед возвратом. Отступ указывает, что возврат выполняется, когда условие выполнено, но оно всегда возвращается.

Другой пример в С# с использованием statment

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

что эквивалентно

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

Ответ 10

Самый подходящий пример, который я могу придумать:

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

С какими if будет спарен else? Отступ подразумевает, что внешний if получает else, но это не так, как его увидит компилятор; внутренний if получит else, а внешний if не будет. Вы должны были бы знать, что (или посмотрите, как это работает в режиме отладки), чтобы выяснить, почему этот код может не оправдать ваши ожидания. Это становится более запутанным, если вы знаете Python; в этом случае вы знаете, что отступ определяет блоки кода, поэтому вы ожидаете, что он будет оцениваться в соответствии с отступом. С#, однако, не дает летящего флип о пробелах.

Теперь, я сказал, я не очень согласен с этим правилом "всегда использовать скобки" на его лице. Это делает код очень вертикально шумным, уменьшая способность быстро его считывать. Если утверждение:

if(someCondition)
   DoSomething();

... тогда это должно быть написано именно так. Утверждение "всегда использовать скобки" звучит как "всегда окружает математические операции с круглыми скобками". Это превратило бы очень простое утверждение a * b + c / d в ((a * b) + (c / d)), введя возможность пропустить близкую пару (проклятие многих кодеров) и для чего? Порядок операций хорошо известен и хорошо соблюдается, поэтому круглые скобки являются излишними. Вы должны использовать только круглые скобки для выполнения другого порядка операций, чем обычно применяется: a * (b+c) / d например. Блочные скобки сходны; используйте их, чтобы определить, что вы хотите делать, в случаях, когда он отличается от значения по умолчанию и не является "очевидным" (субъективным, но обычно довольно обычным).

Ответ 11

Просматривая ответы, никто в явном виде не указал, какую практику я делаю, рассказывая историю вашего кода:

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

становится:

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

Поместите j++ в ту же строку, что и если кто-то должен сигнализировать кому-либо: "Я хочу, чтобы этот блок никогда не увеличивал j". Из coursethis стоит только, если линия настолько упрощена, насколько это возможно, потому что установка точки останова здесь, как говорится в peri, не будет очень полезной.

На самом деле, я просто столкнулся с частью Twitter Storm API, у которой есть этот "сортировка" кода в java, вот фрагмент relvant из кода выполнения, на стр. 43 этого слайд-шоу:

...
Integer Count = counts.get(word);
if (Count=null) count=0;
count++
...

В блоке for loop есть две вещи, поэтому я бы не ввел этот код. I.e никогда:

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

Это ужасно, и я даже не знаю, работает ли это (как предполагалось); не делайте этого. Новые линии и фигурные скобки помогают различать отдельные, но связанные фрагменты кода, точно так же, как запятая или полуколока делают в прозе. Вышеупомянутый блок является столь же плохим действительно длинным предложением с несколькими предложениями и некоторыми другими утверждениями, которые никогда не прерывают или не останавливают, чтобы различать отдельные части.

Если вы действительно хотите телеграфировать кому-то еще, однолинейная работа использует только тернарный оператор или ?: form:

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

Но это сводится к коду-гольфу, и я думаю, что не очень хорошая практика (мне не ясно, должен ли я поставить j ++ с одной стороны : или нет). NB Я не запускал тройной оператор на С++ раньше, я не знаю, работает ли это, но он существует.

Короче:

Представьте, как ваш читатель (т.е. человек, поддерживающий код) интерпретирует вашу историю (код). Сделайте максимально понятным для них. Если вы знаете, что новичок-кодер/ученик поддерживает это, возможно, даже оставить как можно больше {}, просто чтобы они не запутались.

Ответ 12

Это делает ваш код более читаемым, четко определяя сферу ваших циклов и условных блоков. Это также избавляет вас от случайных ошибок.

Ответ 13

wrt 6: Это безопаснее, потому что удаление нулевого указателя является no-op. Поэтому, если вы случайно случайно пройдете этот путь дважды, вы не будете вызывать повреждение памяти, освобождая память, которая является бесплатной или была выделена для чего-то еще.

Это большая проблема со статическими объектами области видимости и синглтонами, которые имеют не очень четкие сроки жизни и, как известно, воссоздаются после их уничтожения.

В большинстве случаев вы можете избежать необходимости этого, используя auto_ptrs

Ответ 14

Мне нравится Luchian принятый ответ, на самом деле я узнал, что он прав, поэтому я всегда использую фигурные скобки, даже для однострочных блоков. Однако лично я делаю исключение при написании фильтра, как вы в своем примере. Это:

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

выглядит захламленным для меня. Он разделяет цикл for и оператор if на отдельные действия, когда на самом деле ваше намерение является единственным действием: считать все целые числа, делящиеся на 2. На более выразительном языке это может быть написано примерно так:

j = [1..100].filter(_%2 == 0).Count

В языках, которые не имеют замыканий, фильтр не может быть выражен в одном выражении, но должен быть циклом for, за которым следует оператор if. Тем не менее, это все еще одно действие в уме программиста, и я считаю, что это должно быть отражено в коде, например:

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

Ответ 15

Один из способов помочь предотвратить ошибки, описанные выше, - это встроить то, что вы хотите, когда вы не используете фигурные скобки. Это значительно усложняет, чтобы не заметить ошибки при попытке изменить код.

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

if (condition) doSomething();
    doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong

Ответ 16

Потому что, когда у вас есть два оператора без {}, легко пропустить проблему. Предположим, что код выглядит так.

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;

Это выглядит хорошо. Проблема с этим очень легко пропустить, особенно когда функция, содержащая код, намного больше. Проблема в том, что goto fail выполняется безоговорочно. Вы легко можете себе представить, как это расстраивает (заставляя спросить, почему последний hash_update всегда терпит неудачу, ведь все хорошо выглядит в функции hash_update).

Однако это не значит, что я за добавление {} повсюду (на мой взгляд, видеть {} повсюду раздражает). Хотя это может вызвать проблемы, это никогда не делалось для моих собственных проектов, так как мой личный стиль кодирования запрещает условные выражения без {}, когда они не находятся на одной строке (да, я согласен с тем, что мой стиль кодировки нетрадиционный, но мне это нравится, и я использую стиль кода проекта при внесении вклада в другие проекты). Это делает код ниже.

if (something) goto fail;

Но не следующий.

if (something)
    goto fail;

Ответ 17

Если вы являетесь компилятором, это не имеет никакого значения. Оба одинаковы.

Но для программистов первый из них более понятен, легко читается и меньше подвержен ошибкам.

Ответ 18

Другой пример добавления фигурных скобок. Как только я искал ошибку и нашел такой код:

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

Если вы читаете метод по очереди, вы заметите, что в методе есть условие, которое возвращает, если оно неверно. Но на самом деле это похоже на 100 других простых обработчиков событий, которые устанавливают некоторые переменные, основанные на некоторых условиях. И в один прекрасный момент приходит быстрый кодер и добавляет в конце метода дополнительную инструкцию по настройке переменной:

{
    ...
    OtherwiseSomeAdditionalStatement3;
    SetAnotherVariableUnconditionnaly;
}

В результате SetAnotherVariableUnconditionnaly выполняется, когда SomeConditionIsMet(), но быстрый парень этого не заметил, потому что все строки почти схожи по размеру, и даже когда условие возврата имеет вертикальный отступ, это не так заметно.

Если условный возврат форматируется следующим образом:

if (!SomeConditionIsMet())
{
    return;
}

это очень заметно, и быстрый кодер найдет его с первого взгляда.

Ответ 19

Я считаю, что первое должно быть четким, а затем вторым. Это дает ощущение закрытия инструкций, при этом мало кода отлично, когда код становится сложным {...} помогает много, даже если это endif или 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++;

Ответ 20

Лучше всего установить указатель на NULL, когда вы закончите с ним.

Вот пример, почему:

Класс A выполняет следующие действия:

  • Выделяет блок памяти
  • Затем через некоторое время он удалит этот блок памяти, но не устанавливает указатель в NULL

Класс B выполняет следующие действия

  • Выделяет память (и в этом случае ему присваивается тот же блок памяти, который был удален классом А.)

В этот момент оба класса A и класс B имеют указатели, указывающие на один и тот же блок памяти, поскольку касается класса A, этот блок памяти не существует, поскольку он завершен с ним.

Рассмотрим следующую задачу:

Что делать, если в классе A возникла логическая ошибка, которая привела к записи в память, которая теперь принадлежит классу B?

В этом конкретном случае вы не получите ошибку с ошибкой плохого доступа, так как адрес памяти является законным, все время класс A теперь эффективно искажает данные класса B.

Класс B может в конечном итоге потерпеть крах, если он встретит неожиданные значения, и когда он рухнет, скорее всего, вы потратите довольно долгое время на поиск этой ошибки в классе B, когда проблема находится в классе A.

Если указатель удаленной памяти был установлен в NULL, вы бы получили ошибку исключения, как только любые логические ошибки в классе A попытались написать указателю NULL.

Если вас беспокоит логическая ошибка с двойным удалением, когда указатели NULL во второй раз, добавьте assert для этого.

Кроме того: если вы собираетесь голосовать, пожалуйста, объясните.

Ответ 21

Я должен признать, что не всегда использовать {} для одной строки, но это хорошая практика.

  • Допустим, вы пишете код без скобок, который выглядит так:

    for (int я = 0; я < 100; ++ i) for (int j = 0; j < 100; ++ j) DoSingleStuff();

И через некоторое время вы хотите добавить в цикл j некоторые другие вещи, и вы просто делаете это путем выравнивания и забываете добавлять скобки.

  • Операция памяти быстрее. Допустим, у вас большой объем и создайте большие массивы внутри (без new, чтобы они были в стеке). Эти массивы удаляются из памяти сразу после того, как вы покидаете область видимости. Но возможно, что вы используете этот массив в одном месте, и он будет в стеке на некоторое время и будет каким-то мусором. Поскольку стек имеет ограниченный и довольно малый размер, можно увеличить размер стека. Поэтому в некоторых случаях лучше написать {}, чтобы предотвратить это. ПРИМЕЧАНИЕ это не для одной строки, а для таких ситуаций:

    if (...) {   // Некоторые вещи...   {//у нас нет if, while и т.д.       //SomeOtherStuff   }   //SomeMoreStuff }

  • Третий способ использования аналогичен второму. Это просто не сделать очиститель стека, а открыть некоторые функции. Если вы используете mutex в длинных функциях, обычно лучше блокировать и разблокировать непосредственно перед доступом к данным и сразу после окончания чтения/записи. ПРИМЕЧАНИЕ, этот способ используется, если у вас есть свои собственные class или struct с constructor и destructor для блокировки памяти.

  • Что еще:

    if (...)  если (...)     Некоторые вещи(); еще  SomeOtherStuff();//переходит ко второму, если, но аллигмент показывает, что он первый...

В целом, я не могу сказать, что лучший способ всегда использовать {} для одной строки, но ничего плохого делать не следует.

ВАЖНОЕ ИЗМЕНЕНИЕ. Если вы пишете компиляцию скобок кода для одной строки, ничего не делает, но если ваш код будет интерпретироваться, он очень медленно замедляет код. Очень немного.

Ответ 22

Всегда иметь фигурные скобки - очень простое и надежное правило. Однако код может выглядеть inelegant, когда есть много брекетов. Если правила позволяют опустить фигурные скобки, тогда должны быть более подробные правила стиля и более сложные инструменты. В противном случае это может легко привести к хаотическому и запутанному (не изящному) коду. Поэтому поиск отдельного правила стиля отдельно от остальных руководств по стилю и используемых инструментов, вероятно, бесплоден. Я просто приведу некоторые важные сведения об этом правиле № 3, о которых даже не упоминалось в других ответах.

Первая интересная деталь заключается в том, что большинство сторонников этого правила соглашаются нарушить ее на случай else. Другими словами, они не требуют в обзоре такого кода:

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

Вместо этого, если они видят это, они могут даже предложить написать это следующим образом:

// 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();
}

Это технически является нарушением этого правила, поскольку между else и if нет фигурных скобок. Такая двойственность правила гласит, когда пытаться применить его к базе кода автоматически с помощью бессмысленного инструмента. Действительно, зачем спорить, просто дайте инструменту применить стиль автоматически.

Вторая деталь (которая также часто забывается сторонниками этого правила) заключается в том, что ошибки, которые могут произойти, никогда не только из-за нарушений этого правила № 3. На самом деле это почти всегда связано с нарушениями правила № 1 (с которым никто не спорит). Опять же, с точки зрения автоматических инструментов, нетрудно сделать инструмент, который немедленно жалуется, когда нарушается правило № 1, и поэтому большинство ошибок могут быть обнаружены своевременно.

Третья деталь (которая часто забывается противниками этого правила) - это путаница природы пустой инструкции, которая представлена ​​одиночной точкой с запятой. Большинство разработчиков, испытывающих некоторый опыт, рано или поздно запутались с единственной неуместной точкой с запятой или пустым оператором, который написан с использованием единственной точки с запятой. Две фигурные скобки вместо одной точки с запятой визуально легче обнаружить.

Ответ 23

Существует несколько возможных способов написания контрольных операторов; некоторые комбинации из них могут сосуществовать без ущерба для удобочитаемости, но другие комбинации могут вызвать проблемы. Стиль

if (condition)
  statement;

будет сосуществовать с некоторыми другими способами написания контрольных утверждений, но не так хорошо с другими. Если многострочные управляемые операторы записываются как:

if (condition)
{
  statement;
  statement;
}

то визуально очевидно, какие операторы if управляют одной строкой и какие из них управляют несколькими строками. Если, однако, многострочные операторы if записываются как:

if (condition) {
  statement;
  statement;
}

тогда вероятность того, что кто-то пытается расширить конструкции с одним выражением if без добавления необходимых фигурных скобок, может быть намного выше.

Оператор строки if с одним оператором на следующей строке также может быть проблематичным, если кодовая база существенно использует форму

if (condition) statement;

Мое собственное предпочтение состоит в том, что наличие инструкции в своей собственной строке обычно повышает удобочитаемость, за исключением случаев, когда существует множество операторов if с аналогичными блоками управления, например

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

в этом случае я обычно буду предшествовать и следовать таким группам операторов if с пустой строкой, чтобы визуально отделить их от другого кода. Наличие ряда инструкций, которые начинаются с if в том же отступе, предоставит четкую визуальную индикацию, что там что-то необычное.