**4.** Если всё тело функции — один `statement`, то его можно разместить на одной строке. При этом, вокруг фигурных скобок ставятся пробелы (кроме пробела на конце строки).
**15.** В классах и структурах, `public`, `private`, `protected` пишется на том же уровне, что и `class/struct`, а остальной код с отступом.
```cpp
template <typenameT>
class MultiVersion
{
public:
/// Version of object for usage. shared_ptr manage lifetime of version.
using Version = std::shared_ptr<constT>;
...
}
```
**16.** Если на весь файл один `namespace` и кроме него ничего существенного нет, то отступ внутри `namespace` не нужен.
**17.** Если блок для выражения `if`, `for`, `while`, ... состоит из одного `statement`, то фигурные скобки не обязательны. Вместо этого поместите `statement` на отдельную строку. Это правило справедливо и для вложенных `if`, `for`, `while`, ...
Если внутренний `statement` содержит фигурные скобки или `else`, то внешний блок следует писать в фигурных скобках.
```cpp
/// Finish write.
for (auto & stream : streams)
stream.second->finalize();
```
**18.** Не должно быть пробелов на концах строк.
**19.** Исходники в кодировке UTF-8.
**20.** В строковых литералах можно использовать не-ASCII.
**27.** Нельзя объявлять несколько переменных разных типов в одном выражении.
```cpp
//incorrect
int x, *y;
```
**28.** C-style cast не используется.
```cpp
//incorrect
std::cerr << (int)c <<; std::endl;
//correct
std::cerr <<static_cast<int>(c) <<std::endl;
```
**29.** В классах и структурах, группируйте отдельно методы и отдельно члены, внутри каждой области видимости.
**30.** Для не очень большого класса/структуры, можно не отделять объявления методов от реализации.
Аналогично для маленьких методов в любых классах/структурах.
Для шаблонных классов/структур, лучше не отделять объявления методов от реализации (так как иначе они всё равно должны быть определены в той же единице трансляции).
**31.** Не обязательно умещать код по ширине в 80 символов. Можно в 140.
**32.** Всегда используйте префиксный инкремент/декремент, если постфиксный не нужен.
```cpp
for (Names::const_iterator it = column_names.begin(); it != column_names.end(); ++it)
Пример взят сресурса [http://home.tamk.fi/~jaalto/course/coding-style/doc/unmaintainable-code/](http://home.tamk.fi/~jaalto/course/coding-style/doc/unmaintainable-code/).
**7.** Нельзя писать мусорные комментарии (автор, дата создания...) в начале каждого файла.
**8.** Однострочные комментарии начинаются с трёх слешей: `///` , многострочные с`/**`. Такие комментарии считаются «документирующими».
Замечание: такие комментарии могут использоваться для генерации документации с помощью Doxygen. Но, фактически, Doxygen не используется, так как для навигации по коду гораздо удобне использовать возможности IDE.
**9.** В начале и конце многострочного комментария, не должно быть пустых строк (кроме строки, на которой закрывается многострочный комментарий).
**10.** Для закомментированных кусков кода, используются обычные, не "документирующие" комментарии.
**11.** Удаляйте закомментированные куски кода перед коммитом.
**12.** Не нужно писать нецензурную брань в комментариях или коде.
**13.** Не пишите прописными буквами. Не используйте излишнее количество знаков препинания.
```cpp
/// WHAT THE FAIL???
```
**14.** Не составляйте из комментариев строки-разделители.
- для имён переменных, всё сокращение пишется маленькими буквами `mysql_connection` (не `mySQL_connection`).
- для имён классов и функций, сохраняются большие буквы в сокращении `MySQLConnection` (не `MySqlConnection`).
**12.** Параметры конструктора, использующиеся сразу же для инициализации соответствующих членов класса, следует назвать также, как и члены класса, добавив подчёркивание в конец.
```cpp
FileQueueProcessor(
const std::string & path_,
const std::string & prefix_,
std::shared_ptr<FileHandler> handler_)
: path(path_),
prefix(prefix_),
handler(handler_),
log(&Logger::get("FileQueueProcessor"))
{
}
```
Также можно называть параметры конструктора так же, как и члены класса (не добавлять подчёркивание), но только если этот параметр не используется в теле конструктора.
**13.** Именование локальных переменных и членов класса никак не отличается (никакие префиксы не нужны).
**15.** Все имена - по английски. Транслит с русского использовать нельзя.
```
не Stroka
```
**16.** Сокращения (из нескольких букв разных слов) в именах можно использовать только если они являются общепринятыми (если для сокращения можно найти расшифровку в английской википедии или сделав поисковый запрос).
```
`AST`, `SQL`.
Не`NVDH` (что-то неведомое)
```
Сокращения в виде обрезанного слова можно использовать, только если такое сокращение является широко используемым.
Впрочем, сокращения также можно использовать, если расшифровка находится рядом в комментарии.
**17.** Имена файлов с исходниками на C++ должны иметь расширение только `.cpp`. Заголовочные файлы - только `.h`.
- Сделайте функцию (`done()` или `finalize()`), которая позволяет заранее выполнить всю работу, в процессе которой может возникнуть исключение. Если эта функция была вызвана, то затем в деструкторе не должно возникать исключений.
- Слишком сложную работу (например, отправку данных по сети) можно вообще не делать в деструкторе, рассчитывая, что пользователь заранее позовёт метод для завершения работы.
- Если в деструкторе возникло исключение, желательно не "проглатывать" его, а вывести информацию в лог (если в этом месте доступен логгер).
-В простых программах, если соответствующие исключения не ловятся, и приводят к завершению работы с записью информации в лог, можно не беспокоиться об исключениях, вылетающих из деструкторов, так как вызов `std::terminate` (в случае `noexcept` по умолчанию в C++11), является приемлимым способом обработки исключения.
Внутри одной функции, можно создать отдельный блок кода, для того, чтобы сделать некоторые переменные локальными в нём, и для того, чтобы соответствующие деструкторы были вызваны при выходе из блока.
- cначала добейтесь более-менее максимальной производительности на одном процессорном ядре, потом можно распараллеливать код, но только если есть необходимость.
- используйте пул потоков для обработки запросов. На данный момент, у нас не было задач, в которых была бы необходимость использовать userspace context switching.
Часто можно сделать так, чтобы отдельные потоки писали данные в разные ячейки памяти (лучше в разные кэш-линии), и не использовать синхронизацию потоков (кроме `joinAll`).
Если потом вам потребовалась отложенная инициализация, то вы можете дописать конструктор по умолчанию (который создаст объект с некорректным состоянием). Или, для небольшого количества объектов, можно использовать `shared_ptr/unique_ptr`.
Логгирование следует использовать, в основном, только в прикладном коде.
Сообщения в логе должны быть написаны на английском языке.
Желательно, чтобы лог был понятен системному администратору.
Не нужно писать ругательства в лог.
В логе используется кодировка UTF-8. Изредка можно использовать в логе не-ASCII символы.
**20.** Ввод-вывод.
Во внутренних циклах (в критичных по производительности участках программы) нельзя использовать `iostreams` (в том числе, ни в коем случае не используйте `stringstream`).
Вместо этого используйте библиотеку `DB/IO`.
**21.** Дата и время.
См. библиотеку `DateLUT`.
**22.** include.
В заголовочном файле используется только `#pragma once`, а include guards писать не нужно.
**23.** using.
`using namespace` не используется. Можно использовать `using` что-то конкретное. Лучше локально, внутри класса или функции.
**24.** Не нужно использовать `trailing return type` для функций, если в этом нет необходимости.
```cpp
[auto f() -> void;]{.strike}
```
**25.** Объявление и инициализация переменных.
```cpp
//right way
std::string s = "Hello";
std::string s{"Hello"};
//wrong way
auto s = std::string{"Hello"};
```
**26.** Для виртуальных функций, пишите `virtual` в базовом классе, а в классах-наследниках, пишите `override` и не пишите `virtual`.
**7.** Коммиты в master не должны ломать сборку проекта.
А работоспособность собранных программ гарантируется только для отдельных ревизий.
**8.** Коммитьте как можно чаще, в том числе и нерабочий код.
Для этого следует использовать бранчи.
Если ваш код в ветке `master` ещё не собирается, исключите его из сборки перед `push`, также вы будете должны его доработать или удалить в течение нескольких дней.
**9.** Для нетривиальных изменений, используются бранчи. Следует загружать бранчи на сервер.
(Но будьте готовы к тому, что иногда вам придётся выкидывать плохие библиотеки из кода.)
**3.** Если в пакетах нет нужной библиотеки, или её версия достаточно старая, или если она собрана не так, как нужно, то можно использовать библиотеку, устанавливаемую не из пакетов.
**4.** Если библиотека достаточно маленькая и у неё нет своей системы сборки, то следует включить её файлы в проект, в директорию `contrib`.
**5.** Предпочтение всегда отдаётся уже использующимся библиотекам.
**3.** Не нужно писать код, если вы ещё не знаете, что будет делать ваша программа, и как будет работать её внутренний цикл.
**4.** В простейших случаях, используйте `using` вместо классов/структур.
**5.** Если есть возможность - не пишите конструкторы копирования, операторы присваивания, деструктор (кроме виртуального, если класс содержит хотя бы одну виртуальную функцию), move-конструкторы и move-присваивания. То есть, чтобы соответствущие функции, генерируемые компилятором, работали правильно. Можно использовать `default`.
**6.** Приветствуется упрощение и уменьшение объёма кода.
Причина - существуют похожие нестандартные функции, например, `memmem`. Мы можем использовать и изредка используем эти функции. Эти функции отсутствуют в `namespace std`.