Как правильно открывать скобки c
Перейти к содержимому

Как правильно открывать скобки c

  • автор:

azoyan / cpp-code-style-guide.md

Кодировка исходных кодов должна быть UTF-8 для комментариев и ASCII для прочего (в т.ч. строковых констант).

Конец строки в файлах должен быть в UNIX формате (LF).

Для форматирования отступа строк требуется использовать символы пробела (SPACE) длиной в 4 (WebKit style guide) пробела. Для форматирования выравнивания текста внутри строк использовать пробелы.

Разрешается «табличное» выравнивание пробелами. (Настраивается в clang-format)

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

Ссылки на алгоритмы

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

Библиотеки и внешние зависимости.

Рекомендуется использование STL библиотеки. При необходимости использования нетривиальных алгоритмов и/или подсистем рекомендуется произвести исследование на предмет наличия готовой библиотеки с открытым исходным кодом и подходящей лицензией. Все внешние зависимости должны быть задокументированы, как минимум: название, лицензия, ссылка на оригинальный исходный код или страницу проекта, используемая версия, накладываемые патчи.

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

Наименования переменных, классов и методов должны быть в нотации Camel:

  • UpperCamelCase
    • Наименования классов
    • Именование статических методов возвращаюищих экземпляр класса

    Акронимы имеют только первую большую букву getUuid(), checkId(), loadFromFtp(), HttpReader, ManagerUi .

    Знак указателя * и ссылки & ставить у типа C++ Core Guidelines

    Указатель это тип ( T* ) и ссылка это тип ( T& ).

    Почему не int * foo() <> ? Оставим такое выражение для умножения. Остаётся два варианта. Необходимо ставить звёздочку у типа данных.

    Звёздочка слева кажется более согласованной Есть сомнения, где ставить звёздочку Комментарий
    Dolphin* dolphin = new Dolphin(); Dolphin *dolphin = new Dolphin(); переменная это указатель, всё хорошо
    dynamic_cast<Dolphin*>(animal); dynamic_cast<Dolphin *>(animal); тут, кажется, не нужен пробел
    Dolphin* getObj() <> Dolphin *getObj() <> что же нам делать.

    Противники ставить эти символы рядом с типом, обычно приводят такой пример: int* a, b; Да, в таком случае, у нас а имеет тип «указатель на инт», а b просто тип инт, и если бы мы писали int *a, *b; мы бы не ошибились. Но, в последнее время, считается дурным тоном объявлять переменные на одной строке. Поэтому.

    Объявляейте переменные на новой строке. C++ Core Guidelines

    Запрещается использовать «магические», числа, значения константы (Clang-tidy: readability-magic-numbers)

    Значение должны быть вынесены в именованные константы, при этом обязательно указание единиц измерения констант (если применимо), а также — для неочевидных констант — источник их значения (например, «значение задаётся в ТЗ» или «подобрано экспериментально»).

    Имя перечисляемого типа должно быть написано по нотации UpperCaseCamel, при этом допускаются безымянные (анонимные). Для неанонимных перечислений обязательно использовать конструкцию enum class , если не нужно неявное приведение к целочисленному типу.

    Перечисления не нужные в header’e, должны распологаться в .cpp

    Если в проекте namespace отсутствует, оборачивайте enum в анонимный namespace . Это не даст другим библиотекам его увидеть и случайно подцепить. (На самом деле, автоматически сгенерируется уникальный namespace )

    Именование членов полей классов (Заимствовано у Qt)

    Поля классов начинаются с префикса m_ (member) с нижним подчеркиванием. Статические члены класса с s_ (static). (Если вам зачем-то понадобились глобальные перменные то, они начинаются с префикса g_ (global)

    Почему не Google Style int x_ ?

    • Удобство. IDE после m_ подскажет все поля класса, при автозаполнении.
    • При поиске легче искать по префиксу m_ , чем выражение *_ , которое может пересекаться со snake_case из стандартной и других библиотек.

    Обязательно нужно использовать фигурные скобки, обозначая начало и конец блока (Clang-tidy: readability-braces-around-statements)

    Вариант 2 плох (хоть и красив), так как время отладки, может оказаться, что вы, остановившись на точке останова в условии блока, не сможете перейти в его тело, следующим шагом вы перейдёте на новую строку. Вариант 3 ещё хуже, потому что можно случайно дописать ещё что-то в начало тела и код на следующей строке не выполнится, либо случайно переставить строчки местами, тогда выполнится только набиолее близкая к if строка.

    Пример правильно оформленного кода

    Объявляйте заголовочный файл класса в самом начале

    Позволяет уменьшить связанность нашего заголовочного файла. Сортируйте так же внутри каждого блока инклудов по алфавиту.

    Требуется использовать модификатор const везде где применимо.

    Обязательно использовать:

    • break после всех case
    • default для всех case
    • explicit для конструкторов с параметрами
    • override для переопределения наследованной виртуальной функции. (Писать virtual при этом не нужно)

    Запрещается использовать:

    • #define для определения констант, следует использовать enum : <type> < NAME = VALUE >; , или static const type , или constexpr type
    • using в заголовочных файлах, и вообще использование using namespace xxx опасно. stackoverflow
    • многострочные комментари
    • оставлять закомментированные или «отключенные» участки кода без указания в комментариях, когда и для чего эти участки кода следует раскомментировать
    • приведение типов в стиле Си, см. далее.

    Используйте приведение в стиле С++, а не в Си-стиле и не функциональное приведение. (-Wold-style-cast)

    Приведение в стиле Си работает в compile-time как и static_cast , const_cast , reinterpret_cast и выполняет следующие преобразования до тех пор, пока не получится:

    • static_cast
    • static_cast + const_cast
    • reinterpret_cast
    • reinterpret_cast + const_cast

    Приведением в стиле С++ вы указываете намерение явно и так их проще найти.

    Используйте списки инициализации и выравнивайте их правильно

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

    Не игнорируйте предупреждение -Wreorder (‘something’ will be initialized after)!

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

    Если вы думаете, что будет напечатано «17 — 17» вы неправы. Наиболее вероятные исходы:

    Связано это с тем, что переменная m_def будет инициализирована раньше переменной m_val. Дополнительно: https://stackoverflow.com/questions/1828037/whats-the-point-of-g-wreorder

    Не вызывайте виртуальные функции в конструкторах и деструкторах!

    Записывайте условия в математическом стиле

    min <= count && count <= max

    Избегайте использования тернарных операторов

    • При отладке непонятно в какое из условий ты попал.
    • Пораждает более агрессивное использование у других программистов.

    Я видел в код, в котором в функцию передавалось несколько аргументов, одинм из которых был результат трёх вложенных тернарных выражений. Отлаживать такое и понять что происходит тяжело. Дополнительно можете почитать вот тут: https://www.viva64.com/ru/b/0391/#ID0EQPBG

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

    Обработка ошибок и проверки

    Принята практика обязательной установки указателей в nullptr , если они никуда не указывают. Соответственно в функциях (и методах классов) обязательно проверять входные параметры, передаваемые по указателям на равенство nullptr . Требуется проверять поля-указатели класса, если в теле функции они разыменовываются. Не проверяются лишь константные указатели а ля SystemCore const* , т.к. они задаются один раз (и тогда проверка производится, если инициализируется неконстантным указателем).

    Проверять на невозможные ситуации требуется с помощью assert из <cassert> . Примером может служить assert с проверкой обязательно передаваемого указателя на nullptr . Если ошибка возникает из-за каких-нибудь внешних данных (например данные, загруженные из файла или сети), то такие ошибки следует обрабатывать либо сразу на месте, либо с помощью исключений давать понять, что возникла ошибка. Выбрасываемые функцией исключения обязательно документировать в комментарии к ней (например в заголовочном файле при описании назначения функции). Все исключения должны так или иначе быть отнаследованы от std::exception .

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

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

    std::tuple и std::pair

    По причине снижения читаемости кода использование std::tuple и std::pair запрещается. Вместо этого рекомендуется создавать структуры с содержательными названиями переменных-членов. Исключение составляет использование std::tuple и std::pair в std::map и других случаях, когда оно предполагается стандартной библиотекой, а также в обобщённом шаблонном коде и для реализации функций сравнения, обмена переменных и т.д. Более подробно на эту тему: http://maintainablecode.logdown.com/posts/158531-stdpair-considered-harmful

    Исключение повторного включения заголовочных файлов. Updated (2019-12-17)

    Для исключения повторного включения заголовочных файлов требуется использовать директиву #pragma once . В настоящий момент все компиляторы С++ её поддерживают.

    Основной недостаток директив #ifndef #define #endif («include guards») — вы не можете гарантировать, что придумали уникальный идентификатор. Подробнее stackoverflow

    Используйте опережающие объявления для внутренних классов

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

    Если необходимо вставить бинарные данные, а не исходный код используйте расширение .inc вместо .h (Google styleguide))

    Не использовать длинные лямбды в месте вызова

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

    Хотя, даже для такого случая гораздо лучше показать названием функции, что она намеревается делать:

    Не используйте вызовы функций в условных блоках, если в этом нет необоходимости.

    Причина та же: при отладке мы сможем посмотреть результаты возврата функции.

    Так же, если у нас цикл

    Если в теле цикла не изменятся размер контейнера, то лучше вынести вызов функции size() из условия.

    Не используйте цепочки из вызовов функций

    Конечно, это красиво записывать цепочки функций

    Однако, это до тех пор, пока этот код пишите вы. и не начали отлаживать чужой код. Что возвращает foo() ? Что возвращает bar() ? Что возвращает baz() ? Вы не поставите точку останова и не посмотрите, какие поля у данных типов. Это может показаться занудно и выглядеть многословно, но такой код удобнее поддерживать:

    К тому же цепочки вызовов и сокращение кода могут спровоцировать писать такой код:

    Здесь поведение определяется реализацией (implementation-defined behavior). Порядок вызова функций в данном случае не определён. И может произойти так, что он сначала будет вызов top() , затем вызов pop() удалит с вершины стека, и затем сделает append к удалённому из стека адресу строки. В итоге SIGSEGV , из-за попытки записи в чужую память.

    Использовать ключевое слово auto только в том случае, где тип можно вывести из контекста Clang-tidy: modernize use auto

    Старайтесь освобождать память на той же странице / в том же классе, где она была выделена.

    Иногда, бывают ситуации когда под рукой нет инструментов для поиска утечек (когда лень или дорого настраивать), то классическим способом проверки является подсчёт количества вызовов new и delete , malloc и free .

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

    Используйте функции стандартной библиотеки для создания умных указателей (например, std::make_shared )

    Вызов std::shared_ptr<Widget> . В этой строчке происходит две динамические аллокации:

    Первая — new Widget .

    Вторая скрыта внутри конструктора shared_ptr . Ему нужен счетчик ссылок, который он динамически аллоцирует где-то в куче.

    Причем в памяти они находятся в разных местах. Если ваше приложение не использует weak pointers , или использует их не сильно, вместо строчки std::shared_ptr<Widget>(new Widget) имеет смысл написать std::make_shared<Widget>() .

    std::make_shared сразу проаллоцирует кусок памяти, где может хранить и Widget , и счетчик ссылок. За счет того, что эти две переменные будут находиться рядом, это более кеш-дружелюбно. Работа с std::shared_ptr станет чуть быстрее, динамических аллокаций будет не две, а одна.

    Просьба не использовать std::move() при возврате локальной переменной. Пример с ошибкой:

    Лишний move блокирует полноценную работу оптимизации для возвращаемого значения (RVO, return value optimization/copy elision)

    Компилятор Clang выводит предупреждение при наличии избыточного std::move() :

    Руководство Google по стилю в C++. Часть 10

    Часть 1. Вступление

    Часть 9. Комментарии
    Часть 10. Форматирование
    Часть 11. Исключения из правил

    Эта статья является переводом части руководства Google по стилю в C++ на русский язык.
    Исходная статья (fork на github), обновляемый перевод.

    Форматирование

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

    Длина строк

    Желательно ограничивать длину строк кода 80-ю символами.
    Это правило немного спорное, однако масса уже существющего кода придерживается этого принципа, и мы также поддерживаем его.

    За
    Приверженцы правила утверждают, что строки длиннее не нужны, а постоянно подгонять размеры окон утомительно. Кроме того, некоторые размещают окна с кодом рядом друг с другом и не могут произвольно увеличивать ширину окон. При этом ширина в 80 символов — исторический стандарт, зачем его менять.

    Другая сторона утверждает, что длинные строки могут улучшить читабельность кода. 80 символов — пережиток мейнфреймов 1960-х. Современные экраны вполне могут показывать более длинные строки.

    80 символов — максимум.

    Строка может превышать предел в 80 символов если:

    • комментарий при разделении потеряет в понятности или лёгкости копирования. Например, комментарий с примером команды или URL-ссылкой, длиннее 80 символов.
    • строковый литерал/имя, длиной более 80 символов. Исключением является тестовый код, который желательно размещать в начале файла.
    • выражения с include.
    • Блокировка от повторного включения
    • using декларации

    Не-ASCII символы

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

    Кодировка hex также допустима, особенно если она улучшает читабельность. Например, «\xEF\xBB\xBF» или u8″\uFEFF» — неразрывный пробел нулевой длины в Юникоде, и который не должен отображаться в правильном UTF-8 тексте.

    Используйте префикс u8 чтобы литералы вида \uXXXX кодировались в UTF-8. Не используйте его для строк, содержащих не-ASCII символы уже закодированные в UTF-8 — можете получить корявый текст если компилятор не распознает исходный код как UTF-8.

    Избегайте использования символов C++11 char16_t и char32_t т.к. они нужны для не-UTF-8 строк. По тем же причинам не используйте wchar_t (кроме случаев работы с Windows API, использующий wchar_t).

    Пробелы против Табуляции

    Используйте только пробелы для отступов. 2 пробела на один отступ.
    Мы используем пробелы для отступов. Не используйте табуляцию в своём коде — настройте свой редактор на вставку пробелов при нажатии клавиши Tab.

    Объявления и определения функций

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

    Пример правильного оформления функции:

    В случае если одной строки мало:

    или, если первый параметр также не помещается:

    • Выбирайте хорошие имена для параметров.
    • Имя параметра можно опустить, если он не используется в определении функции.
    • Если тип возвращаемого значения и имя функции не помещаются в одной строке, тип оставьте на одной строке, имя функции перенесите на следующую. В этом случае не делайте дополнительный отступ перед именем функции.
    • Открывающая круглая скобка всегда находится на одной строке с именем функции.
    • Не вставляйте пробелы между именем функции и открывающей круглой скобкой.
    • Не вставляйте пробелы между круглыми скобками и параметрами.
    • Открывающая фигурная скобка всегда в конце последней строки определения. Не переносите её на новую строку.
    • Закрывающая фигурная скобка располагается либо на отдельной строке, либо на той же строке, где и открывающая скобка.
    • Между закрывающей круглой скобкой и открывающей фигурной скобкой должен быть пробел.
    • Старайтесь выравнивать все параметры.
    • Стандартный отступ — 2 пробела.
    • При переносе параметров на другую строку используйте отступ 4 пробела.

    Неиспользуемый параметры с неочевидным контекстом следует закомментировать в определении функции:

    Атрибуты и макросы старайтесь использовать в начале обьявления или определения функции,
    до типа возвращаемого значения:

    Лямбды

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

    Для захвата переменных по ссылке не ставьте пробел между амперсандом (&) и именем переменной.

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

    Числа с плавающей запятой

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

    Вызов функции

    Следует либо писать весь вызов функции одной строкой, либо размещать аргументы на новой строке. И отступ может быть либо по первому аргументу, либо 4 пробела. Старайтесь минимизировать количество строк, размещайте по несколько аргументов на каждой строке.

    Формат вызова функции:

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

    Допускается размещать аргументы на нескольких строках с отступом в 4 пробела:

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

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

    Или разместите сложный аргумент на отдельной строке и добавьте поясняющий комментарий:

    Если в вызове функции ещё есть аргументы, которые желательно разместить на отдельной строке — размещайте. Решение должно основываться улучшении читабельность кода.

    Иногда аргументы формируют структуру. В этом случае форматируйте аргументы согласно требуемой структуре:

    Форматирование списка инициализации

    Форматируйте список инициализации аналогично вызову функции.

    Если список в скобках следует за именем (например, имя типа или переменной), форматируйте <> как будто это вызов функции с этим именем. Даже если имени нет, считайте что оно есть, только пустое.

    Условия

    Старайтесь не вставлять пробелы с внутренней стороны скобок. Размещайте if и else на разных строках.

    Есть два подхода к форматированию условий. Один допускает пробелы между скобками и условием, другой — нет.

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

    Если используется формат с пробелами:

    Заметьте, что в любом случае должен быть пробел между if и открывающей скобкой. Также нужен пробел между закрывающей скобкой и фигурной скобкой (если она есть).

    Короткие условия можно записать в одну строку, если это улучшит читабельность. Используйте этот вариант только если строка короткая и условие не содержит секцию else.

    Не используйте сокращённый вариант, если есть секция else:

    Обычно фигурные скобки не требуются для короткого условия, однако они допустимы. Также сложные условия или код лучше читаются при наличии фигурных скобок. Часто требуют, чтобы любой if был со скобками.

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

    Циклы и switch-и

    Конструкция switch может использовать скобки для блоков. Описывайте нетривиальные переходы между вариантами. Скобки необязательны для циклов с одним выражением. Пустой цикл должен использовать либо пустое тело в скобках или continue.

    Блоки case в switch могут как быть с фигурными скобками, так быть и без них (на ваш выбор). Если же скобки используются, используйте формат, описанный ниже.

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

    Переход с одной метки на следующую должен быть помечен макросом ABSL_FALLTHROUGH_INTENDED; (определён в absl/base/macros.h).
    Размещайте ABSL_FALLTHROUGH_INTENDED; в точке, где будет переход. Исключение из этого правила — последовательные метки без кода, в этом случае помечать ничего не нужно.

    Скобки являются опциональными для циклов с одной операцией.

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

    Указатели и ссылки

    Вокруг ‘.’ и ‘->’ не ставьте пробелы. Оператор разыменования или взятия адреса должен быть без пробелов.

    Ниже приведены примеры правильного форматирования выражений с указателями и ссылками:

    • ‘.’ и ‘->’ используются без пробелов.
    • Операторы * или & не отделяются пробелами.

    Старайтесь использовать единый стиль в файле кода, при модификации существующего файла применяйте используемое форматирование.

    Допускается объявлять несколько переменных одним выражением. Однако не используйте множественное объявление с указателями или ссылками — это может быть неправильно понято.

    Логические выражения

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

    Например, здесь при переносе оператор AND располагается в конце строки:

    Отметим, что разбиение кода (согласно примеру) производится так, чтобы && и оператор AND завершали строку. Такой стиль чаще используется с коде Google, хотя расположение операторов в начале строки тоже допустимо. Также, можете добавлять дополнительные скобки для улучшения читабельности. Учтите, что использование операторов в виде пунктуации (такие как && и

    ) более предпочтительно, что использование операторов в виде слов and и compl.

    Возвращаемые значения

    Не заключайте простые выражения return в скобки.

    Используйте скобки в return expr; только если бы вы использовали их в выражении вида x = expr;.

    Инициализация переменных и массивов

    Что использовать: =, () или
    <> — это ваш выбор.

    Вы можете выбирать между вариантами =,
    () и <>. Следующие примеры кода корректны:

    Будьте внимательны при использовании списка инициализации для типа, у которого есть конструктор с std::initializer_list.

    Компилятор предпочтёт использовать конструктор std::initializer_list при наличии списка в фигурных скобках. Заметьте, что пустые фигурные скобки <> — это особый случай и будет вызван конструктор по-умолчанию (если он доступен). Для явного использования конструктора без std::initializer_list применяйте круглые скобки вместо фигурных.

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

    Директивы препроцессора

    Знак # (признак директивы препроцессора) должен быть в начале строки.

    Даже если директива препроцессора относится к вложенному коду, директивы пишутся с начала строки.

    Форматирование классов

    Размещайте секции в следующем порядке: public, protected и private. Отступ — один пробел.

    Ниже описан базовый формат для класса (за исключением комментариев, см. описание Комментирование класса):

    • Имя базового класса пишется в той же строке, что и имя наследуемого класса (конечно, с учётом ограничения в 80 символов).
    • Ключевые слова public:, protected:, и private: должны быть с отступом в 1 пробел.
    • Перед каждым из этих ключевых слов должна быть пустая строка (за исключением первого упоминания). Также в маленьких классах пустые строки можно опустить.
    • Не добавляйте пустую строку после этих ключевых слов.
    • Секция public должна быть первой, за ней protected и в конце секция private.
    • См. Порядок объявления для выстраивания деклараций в каждой из этих секций.

    Списки инициализации конструктора

    Списки инициализации конструктора могут быть как в одну строку, так и на нескольких строках с 4-х пробельным отступом.

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

    Форматирование пространств имён

    Содержимое в пространстве имён пишется без отступа.

    Пространство имён не добавляет отступов. Например:

    Не делайте отступов в пространстве имён:

    При объявлении вложенных пространств имён, размещайте каждое объявление на отдельной строке.

    Горизонтальная разбивка

    Используйте горизонтальную разбивку в зависимости от ситуации. Никогда не добавляйте пробелы в конец строки.

    Общие принципы

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

    Циклы и условия
    Операторы
    Шаблоны и приведение типов

    Вертикальная разбивка

    Сведите к минимуму вертикальное разбиение.

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

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

    Открывающая или открывающаяся скобка

    Извиняюсь за, может быть, странный вопрос: как правильно — «открывающая» или «открывающаяся» скобка?

    Писал программу на Си и неожиданно задался таким вопросом. Ответа в Инете не нашел. Статистика по Я запросам одинаковая, если судя по ней можно говорить о правильности написания 🙂

    Хм. Я так подозреваю, что оба варианта верны, т.е. и так, и так правильно.

    Если выбирать одно из двух, то более логичным мне кажется слово «открывающая» от слова «открывает», а не «открывается». Ведь скобка открывает выражение, которое внутри, а потом закрывает. Хотя и постоянно говорят «открывается»-«закрывается».

    ЗЫ. Точной информации у меня нет.

    Eagle, интересный вопрос, можно даже подумать над другим примером:

    Собака кусающая или собака кусающаяся? 🙂

    Или я что-то неправильно трактую в словарях.

    Eagle, (‘ся’===’себя’), т.е. скобка, открывающая себя

    правильно будет открывающаяся.

    Да, у собаки может и то, и другое. Интересно. Можно ли это отнести и к скобкам.

    Похоже, Яндекс за вариант «открывающая».

    Я вот еще что подумал. Вполне возможно, что зависит от контекста. Если скобка одна — она «открывающаяся». Если после нее что-то есть, она «открывающая», т.к. открывает последовательность после себя ☝

    Склонен согласиться. По крайней мере так на слух более правильно. И потом открывающаяся скобка явно говорит о том, что вот мол она ( — скобка, открываюсь я. А открывающая скобка вроде как открывает, но не понятно что.

    Хотя вот подумал сейчас еще, и вот что. Скажем бутылка, в момент открытия, она открывающаяся. А скобка, если в единственном числе, то все же наверное открывающая (что ? — скобки). А вот если во множественном, то уж тогда точно открывающиеся скобки. Ну и вопросики. )

    Зачем нужно всегда ставить фигурные скобки: < и >?

    Я не понимаю, зачем все говорят, что нужно всегда использовать < и >.
    Вот, например, код:

    Зачем тут писать скобки?
    Многие говорят, что для читаемости, но любой программист знает о таком написании, зачем же увеличить код?

    Также лично я не понимаю зачем открытие скобки писать на новой строке, чтобы занять ещё одну лишнюю строку?

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

    Лично мне намного быстрее и удобнее разобрать вот такой код:

    αλεχολυτ's user avatar

    12 ответов 12

    Практика всегда ставить скобки избавляет вас от досадных глупых ошибок.

    Страшилка 1. Жил-был метод с guard condition:

    В один прекрасный день вы собираетесь домой, вас просят быстренько добавить логгирование туда. Ткнули по кнопкам (может быть даже по хоткею для live template), закоммитили:

    И ушли. А кто-то потом тратит пару часов, чтобы найти эту невзрачную ошибку.

    Страшилка 2. Жил был код:

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

    А потом вдруг Что-то Очень Важное перестало работать кроме редких случаев.

    PS. Все совпадения не случайны, а действующие лица не выдуманы.

    Nofate's user avatar

    Ответ на самом деле зависит от языка.

    Некоторые языки (javascript, I’m looking at you) практически требуют специальной расстановки скобок, в их отсутствие код может распарситься неочевидным образом.

    В остальных языках-с-фигурными-скобками (C/C++/Java/C#/. ) расстановка скобок — личное дело каждого, вопрос вкуса. Я лично стараюсь опустить скобки где только возможно, например, в коде

    Другим, наоборот, нравится наличие скобок, так как это позволяет коду

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

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

    VladD's user avatar

    Лично я не понимаю зачем открытие скобки писать на новой строке, что бы занять ещё одну лишнюю строку?

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

    Лично я в таких случаях обычно не ставлю. Могу поставить, если дальше идёт блок else со скобками, да и то не всегда. Почти всегда ставлю в js (и джаве) — там, где принято ставить открывающую на той же строке.

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

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

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

    Как же пытаются решить эту проблему? Говорят, всегда ставим скобки. В таком случае получается такой код:

    Да, здесь уже значительно сложнее ошибиться и как-то не так поступить с этим блоком. Но написан ли этот код красиво? На мой взгляд, нет. Это по прежнему мешанина вызовов методов и проверки условия. Причём, блок кода мы выделили, но таким образом мы ещё и отдалили вызываемый метод от условия.

    А вот как бы я отформатировал этот же код:

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

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

    Потому что это проще сказать. Сказать, "пишите код в читаемом виде" — это как ничего не сказать — автор почти всегда скажет, что его код читаемый. А обговаривать все условия — это сложно. Например, я всегда ставлю скобки, если есть вторая строка — даже если она комментарий.

    Сейчас почти для всех языков IDE имеют автоформатирование. Для чего? Для того ли, чтобы было быстрее писать код? Или всё-таки для того, чтобы более или менее читаемый код мог писать кто угодно? Почему чем язык распространённее (и, в некоторой мере, проще), тем строже правила автоформатирования? Посмотрим на дефаултные настройки в Visual Studio. Для C++ (если я не ошибаюсь) нет автоматического добавления пробелов вокруг бинарных операторов. В C# есть. В VB.NET принудительное жёсткое форматирование отступов при уходе со строки. Случайность ли это? Вот мне кажется, что вряд ли.

    Почему предлагается всегда ставить пробелы у бинарных операторов? Какой вариант читаемее y = a*x*x + b*x + c; или y = a * x * x + b * x + c; ? На мой взгляд первый. Тогда зачем? Да чтобы защититься от такого: y=a*x*x+b*x+c; .

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

    Ну и ещё примерчик. Что лучше?

    но мне бы как-то не хотелось увидеть

    потому что тут сложно зацепиться глазами за блоки.

    Кстати, как вариант, тут может быть

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

    Кстати, с этим вариантом могут быть проблемы с автоформатированием в IDE. Потому что я бы однозначно не хотел увидеть

    такой вариант вообще нечитаемый.

    Так же лично я не понимаю зачем открытие скобки писать на новой строке

    Скобки на новой строке удобны тем, что видно, к какому блоку они относятся.

    Следующий код читаем. Он читаем даже если скобки по какой-то причине съедут.

    А как насчёт варианта со скобкой на той же строке? А если по какой-то причине скобка окажется не там где надо?

    Раньше в VS были проблемы с автоформатирование отступов в Си++, если нет скобок. Кстати, это ещё одна возможная причина, почему скобки надо ставить.

    В языках, где скобки расставляются подобным образом (открывающая на той же строке), я всегда ставлю скобки. И скобки, и отступы, если непонятно.

    Например, вот что станет с кодом выше, если в коде в табами (у просматривающего в 2 пробела) добавили 2 строки (и скобки) с отступами в 4 пробела:

    Благодаря пустой строке после вложенных конструкций, первый код легко читается даже в таком не слишком приглядном виде. А теперь посмотрим на второй вариант:

    И ни одной хорошей мысли при взгляде на это чудо.

    чтобы занять ещё одну лишнюю строку?

    Занятые строки должны быть далеко не на первом месте. Так можно и весь код в одну строку написать. Но вот нужно ли?

    Куда важнее общая читаемость кода. Надо для этого занять лишнюю строку, да хоть 5 — пусть будут. Есть 20 однотипных вызовов 4 методов? Отформатировать столбиками (получится 20 строк) и пофиг, что строки длинные и в них несколько операторов. Кстати, вариант с форматирование столбиками — это практически единственный случай, где я допускаю наличие нескольких операторов в строке.

    Лично мне намного быстрее и удобнее разобрать вот такой код:

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

    Во-вторых, здесь нельзя поставить breakpoint на вызов метода. Так что отладке может помешать.

    Сам использую запись в одну строку только иногда в VB, где есть синтаксис однострочного if.

    А вот такой стиль я виду впервые. Видел такое:

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *