Ненужные фигурные скобки в C ++?

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

Constructor::Constructor() { existing code { New code: do some new fancy stuff here } existing code } 

Каков результат, если таковой имеется, из этого? Что может быть причиной для этого? Откуда эта привычка?

Редактировать:

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

Окружающая среда – это встроенные устройства. Существует много устаревшего кода C, завернутого в одежду C ++. В C-разработчиков C много.

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

Код, окруженный фигурными фигурными скобками, выглядит примерно так:

 { bool isInit; (void)isStillInInitMode(&isInit); if (isInit) { return isInit; } } 

(Не обращайте внимания на код, просто придерживайтесь фигурных скобок …;)) После фигурных скобок есть еще несколько бит, проверка состояния и базовая сигнализация.

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

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

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

    В C++ это, возможно, не так важно, поскольку вы можете вводить новые переменные где угодно, но, возможно, привычка от C , где вы не могли сделать этого до C99. 🙂

    Поскольку C++ имеет деструкторы, он также может быть полезен для автоматического освобождения ресурсов (файлов, мьютексов и т. Д.) При выходе из области, что может сделать вещи более чистыми. Это означает, что вы можете удерживать определенный ресурс на более короткий срок, чем если бы вы его схватили в начале метода.

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

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

    В моем производственном коде я написал что-то вроде этого:

     void f() { //some code - MULTIPLE threads can execute this code at the same time { scoped_lock lock(mutex); //critical section starts here //critical section code //EXACTLY ONE thread can execute this code at a time } //mutex is automatically released here //other code - MULTIPLE threads can execute this code at the same time } 

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

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

    Однако есть еще одна прекрасная причина для этого.

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

    • Этот кусок имеет согласованную концептуальную цель
    • Вот вам весь код
    • И вот комментарий о куске.

    например

     { // update the moving average i= (i+1) mod ARRAYSIZE; sum = sum - A[i]; A[i] = new_value; sum = sum + new_value; average = sum / ARRAYSIZE ; } 

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

    Если вам повезет, ваш редактор будет иметь функцию fold / unfold, которая даже позволит вам скрыть блок.

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

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

    Это то же самое, что и блок if (или while т. Д.), Но без if . Другими словами, вы вводите сферу действия без введения структуры управления.

    Это «явное определение» обычно полезно в следующих случаях:

    1. Чтобы избежать конфликтов имен.
    2. К области using .
    3. Контроль при вызове деструкторов.

    Пример 1:

     { auto my_variable = ... ; // ... } // ... { auto my_variable = ... ; // ... } 

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

    Это также позволяет избежать my_variable использования my_variable из предполагаемого объема.

    Пример 2:

     namespace N1 { class A { }; } namespace N2 { class A { }; } void foo() { { using namespace N1; A a; // N1::A. // ... } { using namespace N2; A a; // N2::A. // ... } } 

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

    Пример 3:

     { MyRaiiClass guard1 = ...; // ... { MyRaiiClass guard2 = ...; // ... } // ~MyRaiiClass for guard2 called. // ... } // ~MyRaiiClass for guard1 called. 

    Это может быть важно для RAII в тех случаях, когда потребность в освобождении ресурсов естественно не «падает» на границы функций или структур управления.

    Это действительно полезно при использовании заблокированных блокировок в сочетании с критическими разделами в многопоточном программировании. Блокировка с привязкой, инициализированная в фигурных скобках (обычно первая команда), выйдет за пределы области действия в конце конца блока, и другие streamи смогут снова запускаться.

    Все остальные уже правильно рассмотрели возможности RAY и RAII, но, поскольку вы упоминаете встроенную среду, есть еще одна потенциальная причина:

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

    Здесь isInit , вероятно, будет в стеке:

     { bool isInit; (void)isStillInInitMode(&isInit); if (isInit) { return isInit; } } 

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

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

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

     // if (false) or if (0) { //experimental optimization } 

    Эта практика полезна в определенных контекстах, таких как отладка, встроенные устройства или персональный код.

    Я согласен с «руахом». Если вы хотите получить хорошее объяснение различных уровней охвата на C, ознакомьтесь с этим постом:

    Различные уровни области применения в приложении C

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

     int unusedInt = 1; int main(void) { int k; for(k = 0; k<10; k++) { int returnValue = myFunction(k); printf("returnValue (int) is: %d (k=%d)",returnValue,k); } for(k = 0; k<100; k++) { char returnValue = myCharacterFunction(k); printf("returnValue (char) is: %c (k=%d)",returnValue,k); } return 0; } 

    В этом конкретном примере я дважды определял returnValue, но поскольку он находится только в области блока, а не в области функций (т. Е. Область действия функции будет, например, объявлять returnValue сразу после int main (void)), я не получить любые compiler errors, так как каждый блок не обращает внимания на временный экземпляр returnValue.

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

    Наконец, обратите внимание на объем переменных, используемых в моем примере кода:

     int: unusedInt: File and global scope (if this were a static int, it would only be file scope) int: k: Function scope int: returnValue: Block scope char: returnValue: Block scope 

    Итак, зачем использовать «ненужные» фигурные скобки?

    • Для целей «Скоринга» (как упоминалось выше)
    • Сделать код более читаемым в некотором роде (в значительной степени похожим на использование #pragma или определение «разделов», которые можно визуализировать)
    • Потому что ты можешь. Просто как тот.

    PS Это не BAD-код; он действителен на 100%. Итак, это скорее вопрос (необычный) вкус.

    После просмотра кода в редактировании я могу сказать, что ненужные скобки, вероятно, (в исходном представлении кодеров) должны быть на 100% понятны, что произойдет во время if / then, даже если это только одна строка, это может быть больше строк позже, и скобки гарантируют, что вы не сделаете ошибку.

     { bool isInit; (void)isStillInInitMode(&isInit); if (isInit) { return isInit; } return -1; } 

    если вышеупомянутое было оригинальным, и удаление «дополнительных» woudl приводит к:

     { bool isInit; (void)isStillInInitMode(&isInit); if (isInit) return isInit; return -1; } 

    то более поздняя модификация может выглядеть так:

     { bool isInit; (void)isStillInInitMode(&isInit); if (isInit) CallSomethingNewHere(); return isInit; return -1; } 

    и это, конечно, вызовет проблему, так как теперь isInit всегда будет возвращен, независимо от if / then.

    Объекты автоматически уничтожаются, когда они выходят за frameworks …

    Другим примером использования являются classы, связанные с UI, особенно Qt.

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

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

     // Start video button {  } // Stop video button { <...> } // Status label { <...> } 

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

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

    Давайте будем гением компьютера.