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

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

  1. Использовать отступ // ОК
  2. Никогда не полагайтесь на приоритет оператора - всегда используйте круглые скобки // ОК
  3. Всегда используйте блок {} - даже для одной строки // не в порядке, почему ???
  4. Константный объект слева от сравнения // ОК
  5. Используйте беззнаковые переменные> = 0 // хороший трюк
  6. Установите для указателя значение NULL после удаления - двойная защита от удаления // неплохо

Мне непонятен 3-й прием: что я получу, поместив одну строку в { ... }?

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

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-й версии?


person JAN    schedule 30.08.2012    source источник
comment
Читаемость и ремонтопригодность. Не сразу очевидно, к какому блоку операторов принадлежит 'j ++' и что добавляемый после него код не будет связан с оператором if.   -  person The Forest And The Trees    schedule 30.08.2012
comment
Мне всегда говорили использовать фигурные скобки {} для этих строк по нескольким причинам. Это делает код более понятным для чтения. Также кому-то еще через шесть месяцев может потребоваться отредактировать ваш код, поэтому ясность важна, а с фигурными скобками вероятность ошибки меньше. В этом нет ничего технически более правильного, это просто вопрос хорошей практики. Имейте в виду, что в проекте могут быть тысячи и тысячи строк кода, которые должен проработать какой-нибудь новичок!   -  person RossC    schedule 30.08.2012
comment
Я делаю это, потому что код меняется, и меня раздражает, когда мне нужно добавить фигурные скобки, чтобы добавить строку кода. Но «всегда» - сильное слово.   -  person Mike Seymour    schedule 30.08.2012
comment
Я не думаю, что 5. Use unsigned for variables that are >= 0 хороший трюк. Если вы уменьшаете unsigned int == 0, вы получите потерю значимости. Что легко может произойти.   -  person Pascal Lécuyot    schedule 30.08.2012
comment
Я не согласен с 6, так как он скроет двойное удаление и потенциально скроет логические ошибки.   -  person Luchian Grigore    schedule 30.08.2012
comment
Я бы не стал беспокоиться о 4. Странно читать код, который он создает, и он выявляет только небольшой класс ошибок, о которых в любом случае должен предупреждать любой компилятор.   -  person Mike Seymour    schedule 30.08.2012
comment
№5 может быть непростым - рассмотрите этот цикл: for (unsigned i = 100; i >= 0; --i).   -  person Archie    schedule 30.08.2012
comment
Кстати, (i % 2 == 0) противоречит (2). Вы полагаетесь на приоритет операторов, и смысл, конечно же, ((i % 2) == 0), а не (i % (2 == 0)). Я бы классифицировал правило 2 как допустимое, но «всегда» неверно.   -  person Steve Jessop    schedule 30.08.2012
comment
@Archie: в этом цикле i не является переменной со значением ›= 0`. Это ›= 0 кроме, когда ожидается отрицательное значение для завершения цикла. Так что он не должен быть беззнаковым, и правило 5 не говорит, что оно должно быть беззнаковым :-)   -  person Steve Jessop    schedule 30.08.2012
comment
@Federico Это в основном, чтобы избежать двойного удаления. У этого подхода есть свои плюсы и минусы. Этот пост должен дать вам более подробную информацию: Является ли хорошей практикой значение NULL для указателя после его удаления?   -  person oyenamit    schedule 30.08.2012
comment
@TheForestAndtheTrees: Не сразу понятно, к какому блоку операторов принадлежит 'j ++' ... Скажите это Гвидо ван Россуму.   -  person P Daddy    schedule 30.08.2012
comment
Никогда не полагаться на приоритет операторов означает, что, по крайней мере, выражение i % 2 == 0 требует скобок: (i % 2) == 0. И, конечно, если вы сделаете что-то вроде i = 2 * j + 1;, вам понадобится несколько круглых скобок: i = ((2 * j) + 1);. Ваш код в конечном итоге будет выглядеть как LISP (много адских глупых скобок. Не то, о чем вы спрашивали, но глупые правила приводят к глупому коду. Некоторые из этих рекомендаций представляют собой решения для кодирования ошибок новичков. Большинство программистов не остаются новичками для долго, и следовать правилам для начинающих - не лучшая идея. Научитесь писать правильный код.   -  person Pete Becker    schedule 30.08.2012
comment
Поскольку вы не сказали иначе, следует предположить, что мы говорим о текущей версии C ++, и поэтому вы не должны использовать необработанные указатели без уважительной причины, и если да, при установке в `` недействительное состояние '' установите для него значение null_ptr   -  person thecoshman    schedule 30.08.2012
comment
Вы не должны использовать delete в современном C ++. Вместо этого всегда используйте умные указатели.   -  person Neil G    schedule 30.08.2012
comment
@ron: std::can<Worms>.open() :)   -  person Component 10    schedule 30.08.2012
comment
Самая популярная причина, по-видимому, заключается в том, что вы можете забыть добавить фигурные скобки, когда позже решите добавить больше операторов в тело цикла. Однако я считаю это преувеличением. Практически каждая IDE, которую я использовал, автоматически исправляет отступы, и такие вещи будут выделяться, как больной палец.   -  person Superbest    schedule 30.08.2012
comment
Я считаю, что это замечательный вопрос с таким количеством ответов и комментариев (в том числе и с ответами), что никто не заметил: основная аудитория кода - это другие программисты и вы сами. Возможно, через много лет в будущем с небольшим знанием этой системы и допущений, которые вы применяете. Всегда предполагайте, что кто-то, читающий ваш код, не укладывается в установленные сроки (производство остановлено сейчас и стоит миллионы долларов в час), он психопат, и знает, где вы живете.   -  person Richard    schedule 30.08.2012
comment
@ Ричард: к сожалению, в таких условиях вы не можете выиграть. Когда предоставляется выбор между двумя правилами, один гипотетический психотик не может прочитать одно, а другой гипотетический психотик не может прочитать другое. Так что, какой бы код вы ни использовали, кто-то обнаружит, что ваш код нечитаем. Под «находит нечитабельным» я имею в виду, он готов возражать против удобочитаемости в контексте идеального стиля, не обязательно, что они на самом деле не могут его прочитать.   -  person Steve Jessop    schedule 30.08.2012
comment
Таким образом, ваш код также работает на Perl без изменений.   -  person Peter Eisentraut    schedule 30.08.2012
comment
Вы говорите, что это C ++? Объекты автоматически вызывают деструкторы, когда они выходят из своей области видимости ... поэтому размещение локальных варов в их блоках освобождает их в конце своего блока, что неплохо иметь в C ++.   -  person Shark    schedule 30.08.2012
comment
Я не могу обойти номер 6. У меня была ошибка, из-за которой я отключил и забыл, что удаляемый мной указатель является общим ресурсом. Если бы после удаления я установил для него значение NULL, моя программа продолжала бы работать, выдавая неправильные ответы. Поскольку я не установил для него значение null, в следующий раз, когда я запустил его, произошел сегментарный сбой, что позволило мне найти настоящую проблему. Никогда не позволяйте компьютеру скрыть ваши логические ошибки и забыть о них.   -  person pR0Ps    schedule 30.08.2012
comment
@SteveJessop Скорее случай, когда гипотетический психотик оказался в крайне напряженной позиции, потому что утверждение не было в блоке и было пропущено в тесте, потому что этот крайний случай не был рассмотрен. Я был обожжен (но не сильно) этим. (Если кто-то, пусть даже психотический, не может читать последовательно отформатированный код любого из распространенных стилей, то основная проблема заключается в их неспособности). TL / DR: не о размещении подтяжек, а об их наличии, и я согласен с правилом № 3 для тех исключительных случаев, которые меня спасают.   -  person Richard    schedule 30.08.2012
comment
@Richard: честно, так что они пойдут за мной с топором, если сделают ошибку при изменении моего кода, но они не пойдут за мной с топором, если посчитают, что мои фигурные скобки мешают им видеть мой код; -) На практике я ставлю фигурные скобки, если только не пишу if (condition) statement; в одной строке, что бывает редко. Так что я должен быть в основном в безопасности от вашего психотика, но не полностью. К сожалению, я поставил открывающую скобку на ту же строку, так что RMS все равно меня достанет.   -  person Steve Jessop    schedule 30.08.2012
comment
Думаю, я согласен только с первым пунктом в этом списке. Вы должны быть уверены в правильности своего кода, потому что вы его тестировали, а не потому, что следовали некоторому набору правил в надежде избежать опечаток.   -  person Winston Ewert    schedule 30.08.2012
comment
@ Лучиан Григоре, я полностью с вами согласен. Двойное удаление обычно является логической ошибкой. Если указатель по дизайну не может быть нулевым, не следует устанавливать его равным нулю.   -  person cleong    schedule 30.08.2012
comment
# 1 - единственное правило, которое не вызывает сомнений   -  person Joren    schedule 31.08.2012
comment
В ваших примерах ваши циклы должны быть for (int i = 0 ; 100 > i ; ++i) (согласно Правилу 4) ...   -  person TMN    schedule 31.08.2012
comment
@TomTanner Вопрос требует обсуждения, аргументов [...] или расширенного обсуждения. Приведенные ниже ответы более чем доказывают это. Но уже проведено 4 повторных голосования, так что будьте уверены, дебаты, аргументы и расширенное обсуждение скоро вернутся к жизни.   -  person jogojapan    schedule 31.08.2012
comment
Есть только OTBS.   -  person DanMan    schedule 01.09.2012
comment
Мое общее правило с круглыми скобками: если мне когда-либо придется спрашивать себя, каков приоритет оператора для выражения, используйте скобки, чтобы сделать его явным. В частности, я предпочитаю использовать скобки для группировки выражений, использующих несколько логических операторов. Я не думаю, что кому-то нужно читать документацию о приоритете операторов, чтобы читать мой код. Но если вы не знаете, как x + 5 * y == z группируются, возможно, вам стоит пройти курс алгебры, прежде чем заниматься программированием.   -  person Nate C-K    schedule 02.09.2012
comment
@ NateC-K Но это зависит от языка. Я знаю по крайней мере один, у которого не есть приоритет оператора, поэтому ваш пример действительно будет проанализирован как ((x + 5) * y) == z   -  person Izkata    schedule 02.09.2012
comment
Константный объект слева от сравнения // ОК. Вы имеете в виду такое сравнение: if (5 == myVar). Мне нравится Йода, но не это много.   -  person Laoujin    schedule 02.09.2012
comment
@Izkata: Если вы программируете на MUMPS или другом подобном языке, очевидно, что правила другие. Но тогда использование паренсов становится делом необходимости, а не стилем, так что это не имеет отношения к этому разговору.   -  person Nate C-K    schedule 04.09.2012
comment
Что, если ваш однопроводной macro ... Хм!   -  person Emadpres    schedule 05.09.2012
comment
@EmAdpres: если это не сработает, вам следует исправить макрос (макрос должен быть синтаксически либо выражением, либо одним оператором), а не добавлять фигурные скобки по всему коду.   -  person Yakov Galka    schedule 27.10.2012
comment
Какая польза? потому что в противном случае вы подвергнете себя риску фатального идиотизма: dwheeler.com/essays /apple-goto-fail.html ... или ваша склонность к небрежному уродливому стилю, ведущему к неудачам - а впоследствии и к бессмысленной непоследовательности - например: lkml.org/lkml/2015/12/14/461 также @Emadpres, фигурные скобки можно использовать в однострочных контекстах, а также вы можете искусственно -бросить макросы с помощью `\` в любом случае   -  person underscore_d    schedule 21.04.2016
comment
Константный объект слева от сравнения // ОК - я так думал. «Это умно, - подумал я! «Я умница, - думала я! «Я избегаю случайного задания, - подумала я! Да - избегая случайного присвоения - при инвертируя необходимое сравнение, не всегда получая это правильно в спешке, и поэтому иногда инвертируют результат и ответ. На самом деле это не очень умно, не стоит риска и сбивает с толку большинство, кто это видит - часто включая себя - вероятно, потому, что это противоречит интуиции и урокам математики. C / ++ принял сомнительное решение по = и ==, но не настолько плохое, чтобы это оправдать.   -  person underscore_d    schedule 21.04.2016


Ответы (23)


Попробуем также изменить 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-й версии?

Что я описал. Есть некоторые преимущества. Но, ИМО, правила «всегда» не всегда применяются. Так что я не полностью поддерживаю

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

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

person Luchian Grigore    schedule 30.08.2012
comment
Красиво, но всего два балла. 1) Еще хуже j ++; i ++; на той же линии, думая, что это нормально, это не так. 2) Хорошая IDE должна сообщать вам, что я не идентифицирован, поскольку он выходит за рамки. - person Science_Fiction; 30.08.2012
comment
@Science_Fiction: Верно, но если вы добавите i++ перед j++, тогда обе переменные все равно будут в области видимости, когда они будут использоваться. - person Mike Seymour; 30.08.2012
comment
Это звучит очень разумно, но игнорирует тот факт, что редактор делает отступ, а не вы, и он будет делать отступ для i++; таким образом, чтобы сразу показать, что он не является частью цикла. (В прошлом это могло быть разумным аргументом, и я видел такие проблемы. Около 20 лет назад. С тех пор не было.) - person James Kanze; 30.08.2012
comment
@ Джеймс: это не факт, но это ваш рабочий процесс. И рабочий процесс у многих, но не у всех. Я не думаю, что обязательно будет ошибкой рассматривать исходный код C ++ как простой текстовый файл, а не вывод редактора WYSIWYG (vi / emacs / Visual Studio), который применяет правила форматирования. Таким образом, это правило не зависит от редактора за пределами того, что вам нужно, но не за пределами того, что люди на самом деле используют для редактирования C ++. Отсюда защита. - person Steve Jessop; 30.08.2012
comment
@JamesKanze Вы действительно полагаетесь на предположение, что все всегда работают в мощных IDE? Последний C, который я написал, был в Nano. Даже с учетом этого, одна из первых вещей, которые я обычно отключаю в IDE, - это автоматический отступ, потому что IDE имеет тенденцию мешать моему нелинейному рабочему процессу, пытаясь исправить мои «ошибки» на основе неполной информации. IDE не очень хорошо справляются с автоматическим отступом от естественного потока каждого программиста. Те программисты, которые используют такие функции, как правило, объединяют свой стиль со своей IDE, что нормально, если вы используете только одну IDE, но не так много, если вы работаете со многими. - person Rushyo; 30.08.2012
comment
@JamesKanze: Готов поспорить, что многие программисты напишут эти две инструкции в одной строке, поскольку они такие короткие. А потом бабах. - person Gorpik; 30.08.2012
comment
В ваших примерах, показывающих реальность того, что делается, следует использовать фигурные скобки, чтобы на 100% было ясно, как компилятор будет обрабатывать короткие примеры. - person thecoshman; 30.08.2012
comment
«Это глупая ошибка, но ее может совершить даже опытный программист». - Как я уже сказал в своем ответе, я этому не верю. Я считаю, что это полностью надуманный случай, который на самом деле не представляет проблемы. - person Konrad Rudolph; 30.08.2012
comment
@KonradRudolph, тебе повезло, что тебе не пришлось исправлять ошибки из-за этого. У меня есть. А в некоторых случаях это совсем не очевидно. - person Luchian Grigore; 30.08.2012
comment
@SteveJessop Источник C ++ - это простой текст, и я регулярно отношусь к нему как к такому, например, используя grep или diff. Но разрабатывать высококачественное программное обеспечение сложно, и было бы глупо не использовать все доступные мне инструменты. Редакторов исходного кода предостаточно; зачем использовать неподходящий инструмент, когда подходящие легко доступны? (А редакторы, которые я видел - трое, о которых вы упомянули - не применяют правила форматирования. Вы всегда можете их переопределить. Но когда неявное форматирование не соответствует вашим ожиданиям, обычно это признак того, что вы сделали ошибку.) - person James Kanze; 30.08.2012
comment
@Gorpik Я никогда не видел руководства по кодированию, которое позволяло бы программисту помещать два оператора в одну строку. - person James Kanze; 30.08.2012
comment
@James: Хорошо, возможно, "принудить" было неправильным словом, и, конечно же, все, что достойная IDE делает с источником, необязательно и настраивается. У неприличных IDE иногда есть свои идеи. Но в той степени, в которой они этого не добиваются, неправильно говорить, что отступы выполняются редактором, а не программистом. Моя предпочтительная степень автоматического отступа в моем редакторе - поддерживать текущий уровень отступа, когда я нажимаю клавишу возврата, и я изменяю его только в том случае, если хочу, чтобы редактор создавал определенный стиль, который не является моим собственным (например, при кодировании на строгий стандарт). - person Steve Jessop; 30.08.2012
comment
И в продолжение того, что происходит из Python ... Вам также необходимо правило, чтобы ставить точку с запятой после каждого (несоставного) оператора. Я обнаруживаю, что забываю об этом чаще, чем о ненужных скобках. - person James Kanze; 30.08.2012
comment
@SteveJessop Интересно. Мне еще предстоит найти редактор, который полностью удовлетворил бы меня, поэтому время от времени я исправляю отступы редактора. Но если редактор сделает первый отступ автоматически, в зависимости от фигурных скобок, круглых скобок и т. Д., В моем наборе текста появилось так много ошибок, что я бы даже не мечтал работать без него. Конечно, компилятор пожалуется позже, но чем раньше я узнаю об ошибке, тем лучше. - person James Kanze; 30.08.2012
comment
Когда я использовал отступы, управляемые редактором, для реального кода, IIRC это было для Java. Это было некоторое время назад, но я не помню, чтобы он вылавливал ошибки, я сделал это, потому что правила отступов Sun (или, по крайней мере, были, может быть, Oracle изменил их) настолько глупы, что у меня возникают проблемы с их отслеживанием вручную. Я определенно не чувствовал его недостатка, когда не использовал его. Однако я обнаружил, что какие бы ошибки ни отлавливала моя инструментальная цепочка, я делаю их чаще, чем ошибки, которых нет. - person Steve Jessop; 30.08.2012
comment
А как насчет языков, отличных от C? Delphi имеет область переменных внутри процедуры, которая далее не локализована. Порядок вызова i ++ (или Inc (i)) или j ++ не расширяет цикл. - person R-D; 30.08.2012
comment
Как эти два главных ответа с их в основном абсурдными предложениями получили такую ​​похвалу голосов (и как этот вопрос стал таким популярным), полностью вне меня; Мне остается только предположить, что люди, работающие с C # и Java, просто отвергли этот c++ вопрос. - person eq-; 01.09.2012
comment
Третья причина, касающаяся вложенных if, происходит МНОГО при исправлении ошибок в устаревшем коде C / C ++ (подумайте о стиле K&R времен до появления надежных IDE). Попытка выяснить, предполагал ли исходный кодировщик, что код должен быть выполнен в том виде, в каком он был написан, или просто испортился, проблематично, когда эти кодировщики давно вышли на пенсию (или мертвы). В тех случаях, когда язык продемонстрировал способность вводить в заблуждение, ясно сформулируйте свои намерения. Будущие поколения будут вам благодарны. - person mtdarland; 04.09.2012
comment
Я сделал много действительно глупых ошибок, но ни одна из них не была вызвана одной строчкой if без скобок. Это один из немногих передовых методов, с которым я просто не согласен. (Этот комментарий укусит меня завтра на работе, подожди) - person Chad Schouggins; 05.09.2012
comment
@ChadSchouggins, ты среди счастливчиков. Я использую {} только тогда, когда я предсказываю, что что-то не так может случиться (отсюда термин «защита»). Мне ничего не стоит окружить выражение {}, но это может избавить вас от неприятностей в будущем, так почему бы и нет? - person Luchian Grigore; 05.09.2012
comment
Это очень хорошее объяснение на примере if else. Спасибо Лучиан Григоре, это действительно здорово. - person Ravia; 05.09.2012
comment
Если вы подозреваете, что кто-то может прийти позже и изменить ваш код, чтобы добавить функциональность, сделайте это. - Я единственный, кто думает, что ВЕСЬ мой код зависит от кого-то (включая меня), который придет через 6 месяцев и изменит функциональность? Суть в том, что это делает код более удобным и читаемым, что должно быть целью всего кода. - person sdm350; 05.09.2012
comment
Я всегда использую {}, даже в тривиальном случае, потому что, когда требуется добавить еще один оператор в тот же блок, эту деталь можно случайно забыть. Поверьте, я видел это слишком много раз, чтобы сказать это. - person Guillermo Gutiérrez; 08.09.2012
comment
Когда я читал первый пример, я думал, что i++ попадет в цикл for (и будет увеличиваться на каждой итерации). Увидев эквивалентный код, я понял, что не заметил, что некоторые фигурные скобки отсутствуют. Так что я определенно думаю, что опытный программист может совершить ту же ошибку. Мое личное правило - никогда не иметь встроенного блока внутри встроенного блока, но я обычно вообще избегаю встроенных блоков, если только они не улучшают читаемость. - person mgthomas99; 02.07.2018

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

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() не всегда вызывается.

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

person ta.speot.is    schedule 30.08.2012
comment
Ох, мальчик !! это определенное поведение, которое must_always_do_this(); будет выполнять, если вы прокомментируете // do_something_else (); - person Mr.Anubis; 30.08.2012
comment
Хороший ответ, но похоже, что в первом предложении все было неправильно, поэтому я исправил. Просто говорю, на случай, если я ошибаюсь, потому что странно, что никто другой это не заметил и не изменил. - person Supr; 30.08.2012
comment
@Supr, как это было впервые написано, он говорит, что трудно нарушить правильный поток, если вы используете фигурные скобки, а затем приводит пример того, как легко сломать, не заключив код в квадратные скобки. - person SeanC; 30.08.2012
comment
@SeanCheshire А, теперь я понимаю, что имелось в виду. Я намеренно интерпретировал изменение как запрещающее действие. Виноват. Отлично, BlueRaja. - person Supr; 30.08.2012
comment
Я столкнулся с этим буквально на днях. if(debug) \n //print(info);. В основном вынул целую библиотеку. - person Kevin; 01.09.2012
comment
Fortunately we caught it in code review. Ой! Это звучит так неправильно. Fortunately we caught it in unit tests. было бы намного лучше! - person BЈовић; 03.09.2012
comment
@ BЈовић Но что, если бы код был в модульном тесте? Уму непостижимо. (Шучу, это устаревшее приложение. Модульных тестов нет.) - person ta.speot.is; 04.09.2012

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

  1. OK
  2. Кто-нибудь действительно напишет (или захочет прочитать) (b*b) - ((4*a)*c)? Некоторые приоритеты очевидны (или должны быть), а лишние скобки только добавляют путаницы. (С другой стороны, вы _должны_ использовать круглые скобки в менее очевидных случаях, даже если вы знаете, что они не нужны.)
  3. Sort of. There are two wide spread conventions for formatting conditionals and loops:
    if ( cond ) {
        code;
    }
    
    and:
    if ( cond )
    {
        code;
    }
    
    In the first, I'd agree with him. The opening { is not that visible, so it's best to assume it's always there. In the second, however, I (and most of the people I've worked with) have no problem with omitting the braces for a single statement. (Provided, of course, that the indentation is systematic and that you use this style consistently. (And a lot of very good programmers, writing very readable code, omit the braces even when formatting the first way.)
  4. НЕТ. Такие вещи, как if ( NULL == ptr ), достаточно уродливы, чтобы затруднять читаемость. Напишите сравнения интуитивно. (Что во многих случаях приводит к константе справа.) Его 4 - плохой совет; все, что делает код неестественным, делает его менее читаемым.
  5. НЕТ. Все, кроме int, зарезервировано для особых случаев. Для опытных программистов C и C ++ использование unsigned сигнализирует о битовых операторах. C ++ не имеет реального кардинального типа (или любого другого эффективного типа поддиапазона); unsigned не работает для числовых значений из-за правил продвижения. Числовые значения, над которыми никакие арифметические операции не имеют смысла, например серийные номера, предположительно могут быть unsigned. Однако я бы возражал против этого, потому что он отправляет неверное сообщение: побитовые операции тоже не имеют смысла. Основное правило состоит в том, что целочисленные типы int, _ если только нет веских причин для использования другого типа.
  6. НЕТ. Систематическое выполнение этого действия вводит в заблуждение и на самом деле ни от чего не защищает. В строгом объектно-ориентированном коде delete this; часто является наиболее частым случаем (и вы не можете установить this в NULL), а в противном случае большинство delete находятся в деструкторах, поэтому вы все равно не сможете получить доступ к указателю позже. И установка его на NULL ничего не делает с любыми другими указателями, плавающими вокруг. Систематическая установка указателя на NULL дает ложное ощущение безопасности и на самом деле ничего вам не дает.

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

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

person James Kanze    schedule 30.08.2012
comment
Число 4 может быть уродливым, но в этом есть цель. Он пытается предотвратить if (ptr = NULL). Я не думаю, что когда-либо использовал delete this, это чаще, чем я видел? Я не склонен думать, что установка указателя на NULL после использования - это плохо, но YMMV. Может быть, это только я, но большинство его рекомендаций не кажутся такими уж плохими. - person Firedragon; 30.08.2012
comment
@Firedragon: большинство компиляторов будут предупреждать о if (ptr = NULL), если вы не укажете его как if ((ptr = NULL)). Должен согласиться с Джеймсом Канце в том, что уродство, связанное с наличием NULL, делает его определенным НЕТ для меня. - person Leo; 30.08.2012
comment
@JamesKanze: Должен сказать, что я не согласен с большей частью того, что вы здесь заявили, хотя я ценю и уважаю ваши аргументы в пользу их достижения. Для опытных программистов C и C ++ использование беззнаковых битовых операторов сигналов. - Я совершенно не согласен: использование битовых операторов сигнализирует об использовании битовых операторов. Для меня использование unsigned указывает на стремление со стороны программиста, что переменная должна представлять только положительные числа. Смешивание с числами со знаком обычно вызывает предупреждение компилятора, что, вероятно, было тем, что имел в виду лектор. - person Component 10; 30.08.2012
comment
Я не согласен со многими из ваших пунктов (особенно 3 и 5), но в любом случае +1, поскольку вы показываете, что догматический список лектора является ошибкой, несмотря ни на что. Такие правила, особенно когда они даются без обоснования, просто плохи. - person Konrad Rudolph; 30.08.2012
comment
Для опытных программистов C и C ++ - использование битовых операторов беззнаковых сигналов Или нет. size_t, кто-нибудь? - person ta.speot.is; 30.08.2012
comment
@ ta.speot.is: size_t, конечно, беззнаковый тип, но это не обязательно тот же тип, что и unsigned, и при его использовании не используется ключевое слово unsigned. ИМО, вы можете во что бы то ни стало использовать size_t для размеров, конечно не unsigned. Но я не уверен, что, когда лектор сказал использовать unsigned, он имел в виду использовать unsigned (на что ответил Джеймс) или использовать беззнаковые типы (из которых size_t является одним). Тогда аргумент этапа 2: следует ли использовать size_t для размеров? Я думаю, что это нормально, но некоторые люди (включая Stroustrup IIRC) не всегда беспокоят, а другие активно избегают этого. - person Steve Jessop; 30.08.2012
comment
@Leo Я на самом деле не склонен использовать этот стиль в своих программах, но просто указал на причину его использования :-) Большинство компиляторов будут предупреждать, чтобы быть уверенным, но некоторые люди игнорируют предупреждения, и если это помогает неопытным разработчикам немедленно обнаруживать ошибки, тогда это не такая уж и плохая вещь. Я думаю, что список причин для правил, как сказал Конрад, должен был предоставить лектор. - person Firedragon; 30.08.2012
comment
Я не совсем осведомлен о ссылках, о которых вы говорите, но я думаю, что Strustroup изобрела и поддержала язык и, вероятно, не обслуживала системы с миллионами строк кода, написанными на нем. И примеры языков для начинающих или о функциях не обязательно включают передовые практики, потому что они могут скрыть суть примера. - person TWiStErRob; 30.08.2012
comment
@ Джеймс Канце, подумайте о цели. Вы сравниваете код, созданный опытным программистом, с учебными примерами. Эти правила устанавливает преподаватель, потому что они представляют собой те ошибки, которые, по его мнению, совершают его ученики. Имея опыт, студенты могут расслабиться или игнорировать эти абсолюты. - person Joshua Shane Liberman; 30.08.2012
comment
@ Component10 В конце концов, вы должны прийти к консенсусу. Проблема в том, что семантика unsigned в C ++ не работает для числовых значений, даже если фактические значения не могут быть отрицательными. Например, такие выражения, как abs( a - b ), дают неверные результаты. - person James Kanze; 30.08.2012
comment
@KonradRudolph :-) Да. Хуже того, что нет никаких причин. Все правила должны иметь обоснование. - person James Kanze; 30.08.2012
comment
@ ta.speot.is Тот факт, что size_t должен быть беззнаковым целым типом, является исторической проблемой для языка. Частично побуждение к тому, чтобы требовать, чтобы он был беззнаковым, на самом деле связан с проблемами с неподписанным. Если бы подпись была сделана зависимой от реализации, было бы еще хуже. (А на 16-битных машинах вы не хотели требовать, чтобы он был больше 16 бит, хотя объекты с размером больше 32 КБ могли существовать и действительно существовали.) - person James Kanze; 30.08.2012
comment
@TWiStErRob Страуструп изобрел язык потому что ему приходилось создавать и поддерживать большие программы. (По крайней мере частично.) - person James Kanze; 30.08.2012
comment
@JoshuaShaneLiberman Некоторые из них (например, предложение использовать unsigned) - плохие правила, особенно для новичков. Я знаю правила интегрального продвижения достаточно хорошо, чтобы обычно избегать ловушек unsigneds, но новичок должен видеть только два числовых типа: double и int. (Формально bool и char также являются числовыми типами, но новичок не должен видеть их как таковые: bool должен принимать только значения true и false, а char всегда должен содержать символы.) - person James Kanze; 30.08.2012
comment
@SteveJessop Правило состоит в том, чтобы активно избегать целочисленных типов без знака. На самом деле я менее строг в этом отношении, чем большинство экспертов; в ограниченном контексте, где я в основном просто сравниваю с std::vector<>::size(), например, я буду использовать size_t. Но общее правило состоит в том, что если есть смысл сравнивать величину разницы между двумя значениями, то вы должны избегать всех беззнаковых целочисленных типов. abs( a - b ) не даст_ вам ожидаемых результатов. - person James Kanze; 30.08.2012
comment
Я понимаю суть дела, но всякий раз, когда это обсуждается, мне интересно, будет ли определение функции distance такой апокалиптической катастрофой. Я бы конечно поддержал схему, где abs для беззнакового типа выдает ошибку или, по крайней мере, предупреждение. Но, как ни крути, корабль плыл на этом: C имеет слишком много неявных преобразований, C ++ представил перегрузки abs, так что вы не можете остановить людей, пишущих abs(a-b). Арифметика по модулю 2 ^ n - это никогда то, что вы хотите, кроме хэшей, а неопределенное поведение при переполнении - это never то, что вы хотите, поэтому все целочисленные типы C ++ принципиально нарушены в одну сторону или Другая. - person Steve Jessop; 30.08.2012
comment
Я бы хотел, чтобы этот ответ был удален, поскольку большая часть ответа и последующего обсуждения не имеет ничего общего с исходным вопросом. Это шум. - person Kristopher Johnson; 30.08.2012
comment
@SteveJessop Эта проблема, скорее всего, связана скорее с неявными преобразованиями, чем с чем-либо еще. Но тот факт, что вычитание беззнаковых типов возвращает беззнаковый тип, также является проблемой. И аргументы в пользу использования unsigned в действительности в значительной степени являются аргументами в пользу наличия типов поддиапазонов. Что тоже может быть неплохой идеей, но это не в C ++ (и, насколько я знаю, это не предлагалось). - person James Kanze; 30.08.2012
comment
@Kristopher Нет, это не шум, это показывает очень важный аспект: а именно то, что, независимо от того, что мы можем думать об отдельных пунктах в списке, составление такого списка как догма единодушно считается плохим. Возможно, это ответ на этот вопрос. - person Konrad Rudolph; 01.09.2012
comment
Я согласен со всем, кроме To experienced C and C++ programmers, the use of unsigned signals bit operators - person Qix - MONICA WAS MISTREATED; 01.08.2013
comment
Я просто должен сказать: что за хрень удалите это ??? никогда на земле не делай этого. Старайтесь никогда не использовать необработанные указатели, unique_ptr намного лучше. Если используются необработанные указатели, то удаление и присвоение nullptr помогает находить ошибки, потому что операции с этими указателями дают вам правильные segfault вместо того, чтобы молча притворяться, что они работают. - person Arne; 06.08.2014
comment
@Arne Непонятно, о чем вы говорите. Большинство указателей в хорошо написанном приложении будут необработанными указателями, поскольку большинство указателей предназначены для навигации (а std::unique_ptr не может использоваться для навигации). А присвоение nullptr тому, что вы только что удалили, обычно пустая трата времени; обычно delete будет в контексте (например, деструкторе), где указатель в любом случае перестанет существовать, а установка одного указателя на nullptr ничего не делает с другими указателями на объект. - person James Kanze; 06.08.2014
comment
@Arne А что касается delete this, то, подходит ли он, зависит от приложения. (При сильной транзакционной целостности, например, delete, возможно, придется подождать до конца транзакции.) Тем не менее, нормальная философия объектно-ориентированного программирования была бы такова, что сами объекты обладают интеллектом и управляют своим собственным временем жизни, удаляя себя в ответ на некоторые внешние мероприятие. - person James Kanze; 06.08.2014
comment
Просто выбросил это туда; есть менее используемый, но все же стандартный тип под названием ssize_t, который подписан size_t. - person Qix - MONICA WAS MISTREATED; 01.04.2016

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

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

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

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

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

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

Первый код краток; второй код раздут.

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

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


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

person Konrad Rudolph    schedule 30.08.2012
comment
+1 за разумный конкурирующий аргумент. Однако я склонен не соглашаться. Возможно, это странно, но мне гораздо труднее читать ваш пример матрицы без дополнительных скобок. Я могу видеть, что первый выглядит лучше, учитывая, что бросок вышибет вас из функции, но для большинства примеров мне нужны скобки. Я также видел, где первая строка функции является условной, за которой следует «возврат», и это тоже не так уж плохо. Но использование этого против возможности ошибок, я думаю, слишком велико. - person Firedragon; 30.08.2012
comment
Если вы не верите в написание кода, который излишне занимает пространство на экране, тогда вам нечего ставить открывающую скобку на отдельной строке. Мне, вероятно, теперь придется уклониться и бежать от святой мести GNU, но серьезно - либо вы хотите, чтобы ваш код был вертикально компактным, либо нет. И если вы это сделаете, не делайте вещей, предназначенных исключительно для того, чтобы сделать ваш код менее компактным по вертикали. Но, как вы говорите, исправив это, вы все равно также захотите удалить лишние фигурные скобки. Или, возможно, просто напишите if (a == nullptr) { throw null_ptr_error("a"); } одной строкой. - person Steve Jessop; 30.08.2012
comment
FWIW, в примере с матрицей я бы лично оставил фигурные скобки, открыв фигурные скобки на той же строке, что и for, и закрывающие фигурные скобки, каждая на отдельной строке. Но у меня не было бы пустой строки после цикла, и у меня может не быть ни одной перед ним, поэтому я бы использовал как минимум на одну строку больше, чем вы предпочитаете. - person Steve Jessop; 30.08.2012
comment
@Steve На самом деле, я ставлю открывающую скобку на предыдущую строку по той самой причине, которую вы указали. Я использовал здесь другой стиль, чтобы было более очевидно, насколько огромной может быть разница. - person Konrad Rudolph; 30.08.2012
comment
+1 Полностью согласен, что ваш первый пример без фигурных скобок читать намного легче. Во втором примере мой личный стиль кодирования заключается в использовании фигурных скобок во внешнем цикле for, а не во внутреннем. Я не согласен с @SteveJessop в том, что нужно быть той или иной крайностью в отношении вертикально компактного кода. Я опускаю дополнительные скобки с однострочными элементами, чтобы уменьшить вертикальное пространство, но я помещаю открывающие скобки на новую строку, потому что мне легче увидеть прицел, когда скобки выровнены. Цель - удобочитаемость, и иногда это означает использование большего вертикального пространства, а иногда - меньшее использование. - person Travesty3; 30.08.2012
comment
Я бы не сказал, что ваш первый пример ужасен, но я нахожу его немного менее читабельным, чем без фигурных скобок. Когда есть вложение, это, вероятно, более читабельно с фигурными скобками, но опять же, с или без них не является серьезной проблемой, при условии, что вы последовательны. На самом деле важным моментом, вероятно, является то, что правило не имеет смысла изолированно. Есть несколько способов написания читаемого кода C ++, основанного на сочетании отступов, фигурных скобок и ряда других вещей. Вы выбираете одно и придерживаетесь его. Но внимание уделяется общему стилю, а не отдельному элементу. - person James Kanze; 30.08.2012
comment
Я никогда не сталкивался с этой проблемой в реальной жизни: тебе повезло. Подобные вещи не просто обжигают вас, они вызывают ожоги третьей степени на 90% (и это всего лишь несколько уровней управления, требующих исправления поздно вечером). - person Richard; 30.08.2012
comment
@ Ричард, я просто на это не куплюсь. Как я объяснил в чате, даже если эта ошибка когда-либо возникнет (что я считаю маловероятным), ее легко исправить, если посмотреть на трассировку стека, потому что очевидно, где ошибка, просто взглянув на код. Ваше преувеличенное утверждение полностью безосновательно. - person Konrad Rudolph; 30.08.2012
comment
Я никогда не сталкивался с этой проблемой в реальной жизни: @Richard прав - это то, что обычно проявляется в самый утомительный момент. - person Thorbjørn Ravn Andersen; 30.08.2012
comment
Если вы пишете код, опуская фигурные скобки, и этот код изменяют другие, и некоторые из этих программистов не так внимательны, как вы, я гарантирую, что в какой-то момент будет сделана ошибка. Может быть, вам не придется иметь дело с этим, потому что вы никогда не допускаете ошибок, но если вы можете помочь предотвратить будущие ошибки, введя два дополнительных символа, почему бы и нет? - person Brian Stormont; 01.09.2012
comment
@Brian Дело не в том, что я не совершал этой ошибки. Дело в том, что я просто не верю, что какие-либо опытные программисты совершают эту ошибку, или, если они ее совершают, они сразу ее поймают и это не причинит вреда. Выше Ричард даже утверждает, что это потребует много тяжелой работы. Я считаю это утверждение совершенно невероятным. - person Konrad Rudolph; 01.09.2012
comment
Я не всегда использую скобки по причинам, изложенным выше. Ответ был дан в контексте вопроса: что дает это правило. Пример из реальной жизни, приведенный в моем ответе, был написан не мной, а кодом коллеги. Если вы правильно используете намерение, очень сложно попасть в положение, когда вы неосознанно меняете операторы управления потоком без скобок. - person ta.speot.is; 02.09.2012
comment
@ ta.speot. Достаточно справедливо. На самом деле Лучиан сказал мне примерно то же самое в чате, поэтому я думаю, что будет справедливым убрать ваши имена из моего ответа. В конце концов, это не личное обвинение. Ваше здоровье. - person Konrad Rudolph; 02.09.2012
comment
У меня нет проблем с моим именем в вашем ответе, особенно в качестве ссылки на мой ответ. В любом случае, спасибо за внимание. - person ta.speot.is; 02.09.2012
comment
goto fail - person Konrad Borowski; 25.05.2014
comment
@xfix Да, goto fail - прекрасный контрпример к этому ответу. Однако я должен согласиться с Конрадом Рудольфом в том, что код, полностью заключенный в скобки, очень уродлив. Лично я не использую ни один из стилей, но помещаю одно тело оператора непосредственно после if() или for() в той же строке. Это предотвращает ошибки типа goto fail и является наиболее лаконичным способом написания такого кода. - person cmaster - reinstate monica; 25.05.2014
comment
@xfix На самом деле, «goto fail» вообще не было бы предотвращено с помощью фигурных скобок. По общему признанию, даже я подумал об этом сначала, но если немного подумать - нет. Строка goto fail;, вероятно, была добавлена ​​в результате слияния системы контроля версий или подобного процесса - даже в коде в фигурных скобках она могла стоять после скобки, вызывая ту же проблему. Настоящий урок здесь таков: используйте правильные уровни предупреждений; все современные компиляторы предупреждают об этом коде. Это никогда не должно было пройти проверку. - person Konrad Rudolph; 26.05.2014
comment
@SteveJessop: если за каждым if, while и т. Д. Следует либо одиночный оператор с отступом, либо {, отступ которого совпадает как с оператором управления, так и с совпадающим }, тогда блоки управления с одним оператором будут легко распознаваемы как таковые. Перемещение { на предыдущую строку затрудняет визуальное подтверждение того, что код действительно структурирован так, как задумано. Я бы сказал, что размещение каждого { в той же строке или столбце, что и его }, добавляет одну строку к сложным управляющим структурам, но позволяет сократить одну строку от простых. Для кода с более простыми структурами управления это победа. - person supercat; 16.07.2015
comment
Теперь я испытал это в дикой природе. Его поймал не разработчик, даже не во время экспертной оценки, а во время тестирования, когда он нарушил ряд функций, которые нам также нужны для тестирования других задач, и сорвал весь наш график. Нет, я понятия не имею, о чем думали вовлеченные люди. - person user3067860; 23.06.2021
comment
@ user3067860 Спасибо за ваш комментарий. Я до сих пор не сталкивался с ошибкой, вызванной этим, но интересно посмотреть, что есть у других, и что это не было обнаружено банально! - Хотя это кажется чрезвычайно редкой ситуацией, и мне все еще интересно, предотвращает ли предотвращение такого редкого события больше ошибок, чем написание более читаемого кода, опуская фигурные скобки (но я в основном пришел к компромиссу, поставив открывающие фигурные скобки на предыдущая строка, которая не сильно влияет на читабельность). - person Konrad Rudolph; 24.06.2021

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

Самый частый проблемный пример, с которым я столкнулся, это:

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, я могу легко закончить с этим, если не буду осторожен:

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 секунда и это может сэкономить вам как минимум несколько запутанных минут отладки, почему бы вам когда-либо не использовать параметр уменьшенной неоднозначности? Мне это кажется ложной экономией.

person jam    schedule 30.08.2012
comment
Разве проблема в этом примере не в неправильном отступе и слишком длинных строках, а не в фигурных скобках? - person Honza Brabec; 30.08.2012
comment
Да, но следование рекомендациям по дизайну / кодированию, которые являются «безопасными» только при условии, что люди также следуют другим рекомендациям (например, не имеют слишком длинных строк), похоже, вызывает проблемы. Если бы фигурные скобки были установлены с самого начала, в этой ситуации было бы невозможно получить неправильный блок if. - person jam; 30.08.2012
comment
Каким образом добавление фигурных скобок (что if(really long...editor){ do_foo;} поможет вам избежать этого случая? Похоже, проблема останется прежней. Лично я предпочитаю избегать фигурных скобок, когда в них нет необходимости, однако это не имеет ничего общего со временем, необходимым для их записи, а с уменьшением удобочитаемость за счет двух лишних строк в коде. - person Grizzly; 31.08.2012
comment
Хороший момент - я предполагал, что принудительное использование скобок также приведет к тому, что они будут помещены в разумное место, но, конечно, кто-то, решивший усложнить задачу, может поставить их в ряд, как в вашем примере. Однако я полагаю, что большинство людей этого не сделает. - person jam; 31.08.2012
comment
Первое и последнее, что я делаю при прикосновении к файлу, - это нажимаю кнопку автоформатирования. Это устраняет большинство из этих проблем. - person Jonathan Allen; 31.08.2012
comment
Если на изготовление фигурных скобок уходит целая секунда, вам следует пойти в класс набора текста. / с - person Qix - MONICA WAS MISTREATED; 01.04.2016

My 2c:

Использовать отступ

Очевидно

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

Я бы не стал использовать слова «никогда и всегда», но в целом считаю это правило полезным. В некоторых языках (Lisp, Smalltalk) это не проблема.

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

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

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

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

Используйте беззнаковые переменные, которые> = 0

OK. Как ни странно, я слышал, что Страуструп не согласен.

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

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

person Nemanja Trifunovic    schedule 30.08.2012
comment
+1 только за последнюю точку. В любом случае необработанный указатель не имеет права владеть памятью. - person Konrad Rudolph; 30.08.2012
comment
Что касается использования без знака: не только Страуструп, но и K&R (в C), Херб Саттер и (я думаю) Скотт Мейерс. Фактически, я никогда не слышал, чтобы кто-нибудь, кто действительно понимал правила C ++, выступал за использование unsigned. - person James Kanze; 30.08.2012
comment
@JamesKanze На самом деле, когда я услышал мнение Страуструпа (конференция в Бостоне в 2008 году), там был Херб Саттер, который тут же не согласился с Бьярном. - person Nemanja Trifunovic; 30.08.2012
comment
@NemanjaTrifunovic Тогда он изменил свое мнение (или я перепутал его с кем-то другим). Я не могу попасть в группы Google отсюда, и я не уверен, какие критерии поиска использовать, но я знаю, что в comp.lang.c++.moderated некоторое время назад было большое обсуждение этого вопроса, и, в конце концов, консенсус был против использования беззнаковый. Включая людей, которые изначально отстаивали это. (Часть консенсуса заключалась в том, что вы избегаете этого, потому что unsigned, как определено в C ++, не работает. Я бы не стал заходить так далеко, но его семантика действительно ограничивает его удобство использования.) - person James Kanze; 30.08.2012
comment
Просто для завершения unsigned не работает, одна из проблем заключается в том, что когда C ++ сравнивает подписанные и беззнаковые типы одинакового размера, он преобразуется в беззнаковый перед выполнением сравнения. Что приводит к изменению стоимости. Преобразование в подписанный не обязательно будет намного лучше; сравнение действительно должно происходить, как если бы оба значения были преобразованы в более крупный тип, который мог бы представлять все значения в любом типе. - person James Kanze; 30.08.2012
comment
@NemanjaTrifunovic Я только что поискал в сети. Вероятно, я имел в виду Скотта Мейерса, а не Херба Саттера. См. aristeia.com/Papers/C++ReportColumns/sep95.pdf - person James Kanze; 30.08.2012
comment
@ Джеймс: Это определенно доказывает, что Мейерс против использования беззнаковых типов, но я нахожу его последний вывод необычным, что ни одна функция не должна возвращать значение больше INT_MAX, потому что (по его словам) важно обслуживать клиентов, которые назначают ее int, когда int не является достаточно большим типом для результата. Таким образом, я уверен, что не unsigned его позиция, но мне интересно, действительно ли эта статья является его окончательным аргументом по этому поводу. Есть ли что-нибудь, что клиент может сделать с таким глупым числом, что это не моя вина как дизайнера интерфейса? - person Steve Jessop; 30.08.2012
comment
Честно говоря, статья была написана в 1995 году, когда 16-битная int была позади, а 64-битная long была впереди. Мы люди, которые используют настоящие компьютеры. Так что, возможно, все упоминания о int следует воспринимать так, как если бы они были intmax_t в современном коде, и тогда можно сделать вывод, что вы не должны стремиться использовать значения, превышающие INTMAX_MAX только ради расширения диапазона, который обрабатывает ваша программа. - person Steve Jessop; 30.08.2012
comment
@SteveJessop Я думаю, вы должны понимать это в контексте функции, возвращающей unsigned. Я уверен, что у него нет проблем с exp(double) возвратом значения больше MAX_INT :-). Но опять же, настоящая проблема - неявные преобразования. int i = exp( 1e6 ); - это совершенно валидный C ++. Страуструп в какой-то момент фактически предложил отказаться от неявных преобразований с потерями, но комитет не заинтересовался. (Интересный вопрос: будет ли unsigned - ›int считаться с потерями. Я бы рассмотрел как unsigned -› int, так и int - ›unsigned с потерями. Что будет иметь большое значение для unsigned правильного - person James Kanze; 30.08.2012
comment
Never have a pointer which points to a deleted or non-existing object. Как это сделать, не меняя указатель после удаления объекта? - person harper; 30.12.2012

он более интуитивно понятен и понятен. Это проясняет намерение.

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

person Alok Save    schedule 30.08.2012
comment
Makes the intent clear +1, это, наверное, самая лаконичная и точная причина. - person Qix - MONICA WAS MISTREATED; 01.04.2016

Чтобы добавить к очень разумным предложениям, приведенным выше, один пример, с которым я столкнулся при рефакторинге некоторого кода, где это становится критическим, был следующим: я изменял очень большую базу кода, чтобы переключиться с одного 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, который позволяет добавлять скобки там, где их нет, и я настоятельно рекомендую это, если вы когда-нибудь окажетесь в том же положении, что и я.

person Component 10    schedule 30.08.2012
comment
Однажды я видел документацию, в которой была замечательная чеканка Microsoftligent. Да, при глобальном поиске и замене можно допустить серьезные ошибки. Это просто означает, что глобальный поиск и замену следует использовать с умом, а не со стороны Microsoft. - person Pete Becker; 30.08.2012
comment
Я знаю, что это не мое вскрытие, но если вы собираетесь выполнять замену текста в исходном коде, вам следует сделать это в соответствии с теми же правилами, которые вы использовали бы для хорошо зарекомендовавшей себя замены текста. на языке: макросы. Вы не должны писать макрос #define FOO() func1(); \ func2(); (с разрывом строки после обратной косой черты), то же самое касается поиска и замены. Тем не менее, я всегда видел продвинутые фигурные скобки в качестве правила стиля именно потому, что это избавляет вас от обертывания всех ваших макросов с несколькими операторами в do .. while(0). Но я не согласен. - person Steve Jessop; 30.08.2012
comment
Кстати, это хорошо зарекомендовало себя в том смысле, что японский спорыш хорошо прижился: я не говорю, что мы должны изо всех сил стараться использовать макросы и замену текста, но я говорю, что когда мы делаем такие вещи, мы должны делать это так, чтобы это работало, а не делать то, что работает только в том случае, если конкретное правило стиля было успешно наложено на всю базу кода :-) - person Steve Jessop; 30.08.2012
comment
@SteveJessop: Вы, конечно, правы, и это хороший аргумент в отношении использования правил макросов. Также согласитесь, что хвост не должен вилять собакой. sed явно не лучший инструмент для выполнения контекстного рефакторинга кода C ++. Тем не менее, в то время не было более подходящих инструментов, и, если честно, я многому научился на своем опыте, таком как описанный выше - вы многому учитесь на своих ошибках. Один из самых важных уроков: делайте все возможное, чтобы защитить свой код и, следовательно, свою репутацию от будущих вмешательств (таких как я!) - person Component 10; 30.08.2012
comment
@SteveJessop Можно также поспорить за подтяжки и пояс. Если вам нужно использовать такие макросы (а мы это делали до C ++ и inline), вам, вероятно, следует стремиться к тому, чтобы они работали как можно больше как функция, используя при необходимости трюк do { ... } while(0) (и множество дополнительных скобок. Но это все равно не помешает вам использовать скобки повсюду, если это домашний стиль. (FWIW: Я работал в местах с различными стилями дома, охватывая все стили, обсуждаемые здесь. Я никогда не находил, чтобы что-то было серьезной проблемой. .) - person James Kanze; 30.08.2012
comment
@James: согласен, я бы определенно защищался от макросов, даже если бы я также защищался о том, чтобы помещать фигурные скобки повсюду в коде, это просто еще одна позиция, с которой я столкнулся. Я думаю, что множество аргументов в пользу удобочитаемости и подверженности ошибкам различных стилей непреднамеренно возникает из-за того, что люди видят что-то удивительное и полагают, что это плохо. Любой стиль, который не является полностью глупым, останется в силе, если все знают, что это такое, потому что они также будут знать, что нужно следить за его подводными камнями. Самые большие проблемы возникают, когда (например) кто-то, кто привык везде использовать фигурные скобки, неправильно читает код без. - person Steve Jessop; 30.08.2012
comment
И я считаю, что чем с большим количеством стилей вы работали, тем более внимательно вы читаете и редактируете код. Таким образом, даже если у вас есть предпочтение, что читать легче всего, вы все равно успешно прочтете другие. Я работал в компании, где разные компоненты были написаны разными командами в разных стилях, и правильное решение - без особого эффекта жаловаться на это в столовой, а не пытаться создать глобальный стиль :-) - person Steve Jessop; 30.08.2012
comment
К счастью, мои изменения были постоянными, а не подстановками времени препроцессора, управляемыми макросами. Однако действуют те же правила. Я действительно предложил клиенту встроенную функцию-оболочку для выполнения преобразования, которое было бы гораздо менее рискованным и более быстрым для реализации, но это было отклонено на том основании, что это будет чрезмерно сбивать с толку будущих сопровождающих, которым не нужно знать об этом. оригинальный API. Я отвлекся - я использовал этот пример в основном для демонстрации того, что автоматическое преобразование одной инструкции во множество может нарушить код, если будет сделано неаккуратно. - person Component 10; 30.08.2012

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

if(condition) return; // OK

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

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

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

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();
    }
}
person Lukasz Madon    schedule 30.08.2012
comment
Просто используйте запятые в заявлении using, и вам не обязательно :) - person Ry-♦; 30.08.2012
comment
@minitech Здесь просто не работает - вы можете использовать запятую только тогда, когда типы равны, а не для неравных типов. Лукас делает это каноническим способом, среда IDE даже форматирует его по-разному (обратите внимание на отсутствие автоматического отступа второго using). - person Konrad Rudolph; 01.09.2012

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

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

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

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

if(someCondition)
   DoSomething();

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

person KeithS    schedule 30.08.2012
comment
@AlexBrown ... именно это я и имел в виду. Правило, изложенное в OP, - всегда использовать скобки, даже для отдельных строк, с чем я не согласен по указанной мною причине. Скобки помогут с самым первым примером кода, потому что код не будет вести себя так, как он имеет отступ; вам придется использовать скобки, чтобы связать else с первым if вместо второго. Пожалуйста, удалите голос против. - person KeithS; 30.08.2012

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

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 запускается безоговорочно. Вы легко можете себе представить, насколько это неприятно (заставляя вас спросить, почему last hash_update всегда дает сбой, в конце концов, в функции hash_update все выглядит нормально).

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

if (something) goto fail;

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

if (something)
    goto fail;
person Konrad Borowski    schedule 25.05.2014
comment
Точно. Только не ставьте (совершенно ненужный) символ новой строки + отступ, и вы полностью обойдете эту проблему, которую все всегда так быстро поднимают. - person Alexander; 02.05.2018

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

person Drona    schedule 30.08.2012

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

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

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

person Tom Tanner    schedule 30.08.2012
comment
Если вам случится пройти этот путь дважды, у вас будет ошибка программирования. Установка указателя на null, чтобы сделать эту ошибку менее опасной, не решает основную проблему. - person Pete Becker; 30.08.2012
comment
Согласен, но я видел, что это рекомендовано раньше, и я считаю, что это в некоторых профессиональных стандартах программирования. Я больше комментировал, почему это придумал профессор плаката, чем когда это было хорошо - person Tom Tanner; 30.08.2012
comment
Следуя тому, что сказал Пит Беккер: это не решает основную проблему, но может ее замаскировать. (Бывают случаи, когда вы устанавливаете указатель на NULL после его удаления. Если NULL - правильное значение для указателя в этих обстоятельствах; например, указатель указывает на кешированное значение, а NULL указывает на недопустимый кеш. Но когда вы видите, как кто-то устанавливает указатель на NULL в качестве последней строки в деструкторе, вы задаетесь вопросом, знает ли он C ++.) - person James Kanze; 30.08.2012

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

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++;
}
person MikeFHay    schedule 30.08.2012
comment
Мне нравится, как всем удается игнорировать for (int i = 0; i < 100; i += 2);, ради продолжения спора об отступах ;-) Вероятно, у нас может быть целая отдельная схватка, как лучше всего выразить логику для каждого i в определенном диапазоне с определенным свойством в C ++ без цикла, используя какую-то кошмарную комбинацию стандартных алгоритмов, filter_iterator и / или counting_iterator. - person Steve Jessop; 30.08.2012
comment
Кроме того, если бы у нас было это, мы могли бы не согласиться с тем, как сделать отступ в результирующем массивном одиночном заявлении. - person Steve Jessop; 30.08.2012
comment
@Steve, это просто пример. Есть множество законных применений этого паттерна. Очевидно, что если вы хотите посчитать числа от 1 до 100, которые делятся на 2, все, что вам нужно сделать, это 100/2. - person MikeFHay; 30.08.2012
comment
Конечно, я знаю, поэтому я абстрагировался от каждого i в определенном диапазоне с определенным свойством. Просто обычно на SO люди очень быстро игнорируют фактический вопрос в пользу совершенно другого подхода к приведенному примеру. Но отступы важны, поэтому мы этого не делаем ;-) - person Steve Jessop; 30.08.2012

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

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

if (condition) doSomething();
    doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong
person Blacktiger    schedule 30.08.2012
comment
Второй вариант приведет к ошибке компиляции, потому что else не связан с if. - person Luchian Grigore; 30.08.2012
comment
Одна не столь очевидная проблема с inline заключается в том, что большинство IDE по умолчанию меняют его на стиль с отступом при использовании своей утилиты автоформатирования. - person Honza Brabec; 30.08.2012
comment
@Honza: это очень острый политический вопрос. Если мы сотрудничаем на основе кода, либо мы должны использовать один и тот же стиль отступов до мельчайших деталей, либо мы оба должны согласиться не автоформатировать существующий код только потому, что. Если первое, то согласованный стиль все еще может включать это, но вам придется либо настроить свою IDE, чтобы уважать его, либо не использовать автоформат. Согласиться с тем, что общий формат - это то, что я использую для автоформатов IDE, - это хорошо, если мы все будем вечно использовать одну и ту же среду IDE, и не очень хорошо в противном случае. - person Steve Jessop; 30.08.2012

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

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++ в ту же строку, где if должен сигнализировать кому-либо еще, я хочу, чтобы этот блок когда-либо увеличивал j. Конечно, это имеет смысл только в том случае, если строка максимально упрощена, потому что здесь ставится точка останова, как peri не особо полезен.

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

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

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

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

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

Если вы действительно хотите передать кому-то телеграф, это однострочное задание, используйте тернарный оператор или _ 7_ форма:

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

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

Суммируя:

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

person Pureferret    schedule 02.09.2012
comment
(1) Размещение оператора в той же строке делает его менее читабельным, не более. Особенно простые мысли, такие как приращение, легко упускаются из виду. Обязательно поместите их на новую строку. (2) Конечно, вы можете поместить свой for цикл в одну строку, почему это не должно работать? Это работает по той же причине, что вы можете опустить фигурные скобки; новая строка просто не имеет значения в C ++. (3) Ваш пример условного оператора, помимо того, что он ужасен, является недопустимым для C ++. - person Konrad Rudolph; 03.09.2012
comment
@KonradRudolph спасибо, я немного ржавый в C ++. Я никогда не говорил, что (1) более читабелен, но это будет означать, что этот фрагмент кода предназначен для того, чтобы быть в сети одной строкой. (2) Мой комментарий был больше о том, что я не смог бы прочитать его и знать, что он работает, будь то вообще или как предполагалось; это пример того, чего не следует делать по этой причине. (3) Спасибо, я давно не писал C ++. Я исправлю это сейчас. - person Pureferret; 03.09.2012
comment
Кроме того, размещение более одного выражения в одной строке затрудняет отладку кода. Как поставить точку останова на втором выражении в этой строке? - person Piotr Perak; 05.09.2012

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

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

person P.P    schedule 30.08.2012
comment
Во всяком случае, кроме открытия { на собственной строке. - person Rob; 31.08.2012

Еще один пример добавления фигурных скобок. Однажды я искал ошибку и нашел такой код:

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

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

{
    ...
    OtherwiseSomeAdditionalStatement3;
    SetAnotherVariableUnconditionnaly;
}

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

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

if (!SomeConditionIsMet())
{
    return;
}

он очень заметен, и Fast Coder обнаружит его с первого взгляда.

person Artemix    schedule 05.09.2012
comment
Если вашему быстрому кодировщику не мешает обнаружить выделенный синтаксисом оператор return в теле функции перед добавлением к нему чего-либо, вы не должны позволять быстрому кодировщику приближаться к вашему коду. Вы не помешаете такому парню возиться с вашим кодом, добавив фигурные скобки. - person cmaster - reinstate monica; 25.05.2014
comment
@cmaster Он больше с нами не работает. В любом случае, подсветка синтаксиса - это хорошо, но помните, что есть люди, которые не видят ясно (в прошлом году я видел даже пост слепого программиста). - person Artemix; 26.05.2014

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

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

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

Класс A делает следующее:

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

Класс B делает следующее

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

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

Рассмотрим следующую проблему:

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

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

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

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

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

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

person John    schedule 30.08.2012
comment
Если возникла логическая ошибка, ее надо исправить, а не замаскировать. - person uınbɐɥs; 04.09.2012
comment
@Barmar, OP говорит ... 6. После удаления установите для указателя значение NULL - защита от двойного удаления // неплохо. Некоторые люди ответили, что не устанавливают для него значение NULL, и я говорю, почему он должен быть установлен в NULL, какая часть 6. мой ответ на установку NULL не подходит для 6? - person John; 08.09.2012
comment
@Shaquin, а как вы вообще предлагаете найти эти логические ошибки? После того, как вы установите для переменной-указателя значение NULL после удаления памяти. Любая попытка ссылаться на NULL-указатель приведет к сбою отладчика в строке, в которой была сделана ваша незаконная попытка. Вы можете отследить, где была логическая ошибка, и устранить проблему. Если вы не установите для переменной-указателя значение NULL после того, как вы удалили память, ваша незаконная попытка записать эту удаленную память из-за логических ошибок UNAWARE может быть успешной и, следовательно, не приведет к сбою в этой точке. Это не маскирует. - person John; 08.09.2012

Всегда иметь фигурные скобки - очень простое и надежное правило. Однако при большом количестве фигурных скобок код может выглядеть неэлегантно. Если правила позволяют опускать фигурные скобки, тогда должны быть более подробные правила стиля и более сложные инструменты. В противном случае это может легко привести к хаотичному и запутанному (не элегантному) коду. Поэтому поиск единого правила стиля отдельно от остальных руководств по стилю и используемых инструментов, скорее всего, бесполезен. Я просто приведу некоторые важные детали этого правила № 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, и поэтому большинство ошибок можно было бы обнаружить вовремя.

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

person Öö Tiib    schedule 30.07.2013

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

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

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

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

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

    if (...) {// SomeStuff ... {// у нас нет if, while и т. д. // SomeOtherStuff} // SomeMoreStuff}

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

  • Что еще:

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

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

ВАЖНОЕ РЕДАКТИРОВАНИЕ. Если вы пишете скобки компиляции кода для одной строки, ничего не происходит, но если ваш код будет интерпретироваться, это очень незначительно замедлит код. Совсем немного.

person ST3    schedule 30.07.2013

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

if (condition)
  statement;

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

if (condition)
{
  statement;
  statement;
}

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

if (condition) {
  statement;
  statement;
}

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

Оператор "single-statement-on-next line 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 в одном и том же отступе, обеспечит четкое визуальное указание на то, что есть что-то необычное.

person supercat    schedule 16.07.2015