Project

General

Profile

CodeStyle » History » Version 1

Redmine Admin, 03/23/2024 12:46 PM

1 1 Redmine Admin
# Стиль кодирования на C++
2
3
{{toc}}
4
5
Данный стиль кодирования основан на 
6
Google C++ Style Guide(attachment:cppguide.pdf). В отличие от Google 
7
мы не испытываем страха перед исключениями, помимо этого, у нас свои соглашения 
8
об именовании переменных, констант и функций. На ~80%, текст соответствует 
9
переводу с хабра.
10
11
## Введение
12
13
Цель руководства — управление сложностью кода, путем описания в деталях как 
14
стоит (или не стоит) писать код на C++. Правила этого руководства упростят 
15
управление кодом и увеличат продуктивность программистов.
16
17
*Стиль кодирования (codestyle)* — соглашения, которым следует C++ код. Стиль — 
18
это больше, чем форматирование файла с кодом.
19
20
> *Примечание:* это руководство не является учебником по C++: предполагается, 
21
> что вы знакомы с языком.
22
23
### Цели Руководства по стилю
24
25
Зачем нужен этот документ?
26
27
Есть несколько основных целей этого документа, лежащих в основе отдельных 
28
правил. Используя эти цели можно избежать длинных дискуссий: почему правила 
29
такие и зачем им следовать. Если вы понимаете цели каждого правила, то вам легче
30
с ними согласиться или отвергнуть, оценить альтернативы при изменении правил 
31
под себя.
32
33
Цели руководства следующие:
34
35
 * Правила должны стоить изменений
36
   * Преимущества от использования единого стиля должны перевешивать 
37
   недовольство инженеров по запоминанию и использованию правил.
38
   * Преимущество оценивается по сравнению с кодовой базой без применения 
39
   правил, поэтому если ваши люди всё равно не будут применять правила, то 
40
   выгода будет очень небольшой.
41
   * Этот принцип объясняет почему некоторые правила отсутствуют: например, 
42
   `goto` нарушает многие принципы, однако он практически не используется, 
43
   поэтому Руководство это не описывает.
44
 * Удобство для читателя, а не для писателя
45
   * Кодовая база (и большинство отдельных компонентов из неё) будет 
46
   использоваться продолжительное время. Поэтому, на чтение этого кода будет 
47
   тратиться существенно больше времени, чем на написание.
48
   * Код должен легко читаться, поддерживаться и отлаживаться. Как следствие,
49
   принцип *оставь подсказку для читателя, когда код работает странно*. Если код
50
   работает неочевидно, следует использовать такие конструкции, которые явным 
51
   образом укажут, как именно он работает. Например, использование 
52
   `std::unique_ptr` **явно** показывает передачу владения.
53
   * Кадры приходят и уходят, а хорошо читаемый код позволяет новым специалистам
54
   быстрее вникать в работу
55
 * Согласование с существующим кодом
56
   * Использование единого стиля на кодовой базе позволяет переключиться на 
57
   другие, более важные, вопросы.
58
   * Согласованность позволяет использовать автоматическое форматирование кода. 
59
     Если код всегда написан похожим образом, то и автоформатирование будет 
60
     давать похожий результат.
61
   * Во многих случаях *согласованность* вырождается до: *выбери из нескольких*
62
   *вариантов самый подходящий*, а некоторая гибкость в использовании правил 
63
   позволяет людям меньше спорить.
64
 * По возможности, код должен быть согласован с кодом максимально широкого 
65
 C++-сообщества
66
   * Согласованность кода с кодом других организаций и сообществ весьма полезна. 
67
   Если возможности стандартного C++ или принятые идиомы языка облегчают 
68
   написание программ, это повод их использовать. Однако иногда особенности 
69
   стандарта и идиомы имеют изъяны или неприменимы для внедрения в текущую 
70
   кодовую базу. В этих случаях (как описано ниже) имеет смысл ограничить или 
71
   запретить использование некоторых стандартных возможностей. В некоторых 
72
   случаях создаётся свое решение, которое работает поверх стандартных 
73
   библиотек, иногда это слишком затратно.
74
 * Минимизация неочевидных или опасных конструкций
75
   * Некоторые особенности языка С++ более неочевидны, чем может показаться на 
76
   первый взгляд. Стоит избегать конструкций, если их использование несет больше
77
   рисков, чем пользы.
78
 * Минимизация конструкций, сложных или трудно поддерживаемых для 
79
 среднестатистического программиста на C++
80
   * В C++ есть возможности, которые в целом не приветствуются по причине 
81
   усложнения кода. В часто используемом коде применение хитрых конструкций 
82
   оправданно, поскольку однократные затраты на понимание сложных вещей будут 
83
   оправданы преимуществами от более сложной реализации. 
84
   * Код переходит из рук в руки, а специалисты меняются, поэтому ситуация, 
85
   когда все в команде понимают какой-то сложный фрагмент кода может поменяться 
86
   со временем.
87
 * Масштаб кода должен учитываться
88
   * С кодовой базой более 100 миллионов строк и тысячами инженеров, ошибки и 
89
   упрощения могут дорого обойтись. Например, важно избегать замусоривания 
90
   глобального пространства имён: коллизии имён очень сложно избежать в большой 
91
   кодовой базе если всё объявляется в глобальном пространстве имён.
92
 * Использование оптимизации по мере необходимости
93
   * Оптимизация производительности иногда важнее, чем следование правилам в 
94
   кодировании.
95
96
Намерение этого документа — обеспечить максимально понятное руководство при 
97
разумных ограничениях. Как всегда, здравый смысл всегда превалирует над 
98
документом. Относитесь со скепсисом к хитрым или необычным конструкциям: 
99
отсутствие ограничения не всегда есть разрешение. И, если не можешь решить сам, 
100
спроси начальника.
101
102
### Версия C++
103
104
Сейчас код должен соответствовать C++17, т.е. возможности C++2x нежелательны. 
105
В дальнейшем, руководство будет корректироваться на более новые версии C++.
106
Не используйте нестандартные расширения. Учитывайте совместимость с другим 
107
окружением, если собираетесь использовать C++14 и C++17 в своём проекте.
108
109
## Заголовочные файлы
110
111
В общем случае, каждый `.cpp`-файл должен иметь парный `.hpp` файл. Есть 
112
исключения, например, модульные тесты или небольшие файлы, содержащие только 
113
функцию `main()`.
114
115
Корректное использование заголовочных файлов может иметь огромное влияние на 
116
читаемость, размер и производительность кода.
117
118
Нижеописанные правила помогут вам избежать различных трудностей при 
119
использовании заголовочных файлов.
120
121
### Самодостаточные заголовочные файлы
122
123
Заголовочные файлы должны быть *самодостаточными* и иметь расширение `.hpp`. 
124
Незаголовочные файлы, предназначенные для включения в код, должны быть с 
125
расширением `.inc` и использоваться осторожно.
126
127
*Самодостаточность (self-containment)* заголовочного файла означает, что 
128
пользователи или утилиты для рефакторинга должны включать заголовочный файл без
129
каких-либо дополнительных условий. Например, файл `a.hpp` не должен требовать, 
130
чтобы в файл с исходным кодом также был включен файл `b.cpp`.
131
Заголовочный файл должен иметь защиту от повторного включения и включать все 
132
необходимые файлы.
133
134
При объявлении в заголовочном файле inline-функций или шаблонов, которые будут 
135
использоваться пользователем данного файла, определения этих функций или 
136
шаблонов должны присутствовать либо в самом заголовочном файле, либо в файле, 
137
включенном непосредственно в него. Не следует переносить определения в отдельный
138
заголовочный файл (`inl.hpp`). Так раньше было принято, но теперь это 
139
нежелательно. Если все специализации шаблона явно определены в `.cpp`-файле или 
140
если шаблон используется только в нем, определение шаблона можно оставить в этом 
141
файле.
142
143
В редких случаях включаемые файлы не являются самодостаточными и включаются в 
144
середину другого файла. Такие файлы могут не иметь защиты от повторного 
145
включения и не включать заголовочные файлы с зависимостями. Такие файлы должны 
146
иметь расширение `.inc` и использоваться редко. Использование самодостаточных 
147
заголовочных файлов остается предпочтительным.
148
149
### Защита от повторного включения
150
151
Предпочтительнее использовать директиву `#pragma once`, чем пару 
152
`#ifndef/#define/#endif`. Это связано с тем, что последний нарушает принцип DRY, 
153
поскольку название заголовочного файла фигурирует в нескольких местах и при 
154
рефакторинге приходится менять и сами макросы. 
155
156
В некоторых случаях, например, если возможно включение одного и того же файла 
157
из разных мест, `#pragma once` может не работать. В подобных ситуациях или 
158
где-то еще, можно использовать макросы. В этом случае формат макроопределения 
159
иметь следующий вид:`<PROJECT>_<PATH>_<FILE>_H_`. Например, файл 
160
`foo/src/bar/baz.h` в проекте foo может иметь следующую блокировку:
161
162
```c++
163
#ifndef FOO_BAR_BAZ_H_
164
#define FOO_BAR_BAZ_H_
165
...
166
#endif // FOO_BAR_BAZ_H_
167
```
168
169
### Включайте только то, что используете
170
171
Если файл ссылается на сущность, определенную в другом месте, этот файл должен 
172
напрямую включать заголовочный файл, который предоставляет объявление или 
173
определение данной сущности. Заголовочный файл не должен включаться по 
174
какой-либо другой причине.
175
176
Не стоит рассчитывать на то, что данный заголовочный файл подключается 
177
опосредованно, через какой-то другой. В процессе работы над тем файлом, 
178
ненужное `#include`-выражение может быть убрано. Таким образом, файл `foo.cpp` 
179
должен напрямую включать `bar.hpp`, при использовании сущностей, объявленных 
180
там, даже если файл `foo.hpp` также его включает. Это один из аспектов 
181
самодостаточности.
182
183
### Предварительное объявление
184
185
Избегайте использования предварительных объявлений в `.cpp`-файлах, если это 
186
возможно. Вместо этого включайте нужные файлы.
187
188
*Предварительное объявление (forward declaration)* - это объявление сущности без 
189
определения, например:
190
191
```c++
192
// In a C++ source file:
193
class B;
194
void FuncInB();
195
extern int variable_in_b;
196
ABSL_DECLARE_FLAG(flag_in_b);
197
```
198
199
 * Предварительное объявление может уменьшить время компиляции. Использование 
200
 `#include` требует от компилятора сразу открывать и обрабатывать больше файлов.
201
 * Предварительное объявление позволит избежать ненужной перекомпиляции. 
202
 Применение `#include` может привести к частой перекомпиляции из-за различных 
203
 изменений в заголовочных файлах.
204
205
---
206
207
 * Предварительное объявление может скрывать зависимости от перекомпиляции при 
208
 изменении заголовочных файлов.
209
 * Предварительное объявление хуже обрабатывается специальными утилитами.
210
 * При изменении API, предварительное объявление может стать некорректным. 
211
 Как результат, предварительное объявление функции или шаблонов может 
212
 блокировать изменение API: замена типов параметров на похожий, добавление 
213
 параметров по умолчанию в шаблон, перенос в новое пространство имён.
214
 * Предварительное объявление символов из std:: может вызвать неопределённое 
215
 поведение.
216
 * Иногда тяжело понять, что лучше подходит: предварительное объявление или 
217
 обычный `#include`. Однако, замена `#include` на предварительное объявление 
218
 может (без предупреждений) поменять смысл кода:
219
220
```c++
221
// b.hpp:
222
struct B {};
223
struct D : B {};
224
```
225
226
``` c++
227
// good_user.cpp:
228
#include "b.hpp"
229
230
void f(B*);
231
void f(void*);
232
void test(D* x) { f(x); } // calls f(B*)
233
```
234
235
Если в коде заменить `#include` на предварительное объявление для структур 
236
`B` и `D`, то `test()` будет вызывать `f(void*)`.
237
* Предварительное объявление множества сущностей может быть чересчур объёмным, 
238
и может быть проще подключить заголовочный файл.
239
* Структура кода, допускающая предварительное объявление 
240
(и, далее, использование указателей в качестве членов класса) может сделать код 
241
запутанным и медленным.
242
243
---
244
245
_Вывод:_
246
При всем этом, использование предварительного объявления классов в заголовочном 
247
файле практически лишено данных минусов. Предварительное объявление шаблонных 
248
классов выглядит громоздким и его следует избегать. В `.cpp`-файлах следует
249
избегать предварительных определений.
250
251
### Inline-функции
252
253
Inline-функции (встраиваемые функции) - это функции, тело которой 
254
подставляется непосредственно в код при каждом вызове.
255
256
Определяйте функции как встраиваемые только когда они маленькие, например не 
257
более 10 строк.
258
259
Встраивание функций может генерировать более эффективный код, особенно когда 
260
функции очень маленькие. Такие функции удобно использовать для get/set-функции 
261
или коротких, но критичных для производительности функций.
262
263
Чрезмерное использование inline-функций может существенно замедлить программу. 
264
В зависимости от размера, их использование может как увеличить, так и уменьшить 
265
размер кода. На современных процессорах более компактный код выполняется быстрее
266
благодаря лучшему использованию кэша инструкций.
267
268
_Вывод:_
269
270
*Хорошее правило*: не объявлять функции встраиваемыми, если они длиннее 10 
271
строк. Осторожно с деструкторами! Деструктор неявно вызывает деструкторы 
272
родительских классов.
273
*Еще одно правило*: нет смысла делать функции встраиваемыми, если в них есть 
274
`switch` или цикл.
275
276
Важно понимать, что не всегда директива `inline` делает функцию встраиваемой, 
277
это зависит от компилятора. Например, виртуальные методы и рекурсивные функции 
278
небольшой размер, например get/set-функции.
279
280
### Названия и порядок включения заголовочных файлов
281
282
Включение заголовочных файлов должно производиться в следующем порядке: 
283
Связанный заголовочный файл, Системные заголовочные файлы на языке C, 
284
Файлы стандартной библиотеки, Другие библиотеки, Заголовочные файлы текущего 
285
проекта.
286
287
Все заголовочные файлы проекта должны указываться относительно директории 
288
исходных файлов проекта без использования таких UNIX псевдонимов как . 
289
(текущая директория) или .. (родительская директория). Например, 
290
`awesome-project/src/base/logging.hpp` должен включаться так:
291
292
``` c++
293
#include "base/logging.hpp"
294
```
295
296
Другой пример: если основная функция файлов `dir/foo.cpp` и `dir/foo_test.cpp` 
297
это реализация и тестирование кода, объявленного в `dir2/foo2.hpp`, 
298
то записывайте заголовочные файлы в следующем порядке:
299
300
1. `dir2/foo2.h`.
301
2. Пустая строка.
302
3. Системные заголовочные файлы C (точнее: файлы с включением угловыми скобками 
303
с расширением `.h`), например `<unistd.h>`, `<stdlib.h>`.
304
4. Пустая строка.
305
5. Заголовочные файлы стандартной библиотеки C++ (без расширения в файлах), 
306
например `<algorithm>`, `<cstddef>`.
307
6. Пустая строка.
308
7. Заголовочные `.h/.hpp` файлы других библиотек.
309
8. Пустая строка.
310
9. Файлы `.hpp` вашего проекта.
311
312
Отделяйте каждую непустую группу файлов пустой строкой.
313
314
Такой порядок файлов позволяет выявить ошибки, когда в парном заголовочном файле 
315
(`dir2/foo2.hpp`) пропущены необходимые заголовочные файлы (системные и др.) и 
316
сборка соответствующих файлов `dir/foo.cpp` или `dir/foo_test.cc` 
317
завершится ошибкой. Как результат, ошибка сразу же появится у разработчика, 
318
работающего с этими файлами (а не у другой команды, которая только использует 
319
внешнюю библиотеку).
320
321
Учтите, что заголовочные файлы C, такие как `stddef.h` обычно взаимозаменяемы
322
 соответствующими файлами C++ (`cstddef`). Можно использовать любой вариант, 
323
но лучше следовать стилю существующего кода.
324
325
Внутри каждой секции заголовочные файлы следует перечислять в 
326
алфавитном порядке. Учтите, что ранее написанный код может не следовать этому 
327
правилу. По возможности (например, при исправлениях в файле), исправляйте 
328
порядок файлов на правильный, если это удобно.
329
330
Например, список заголовочных файлов в 
331
`awesome-project/src/foo/internal/fooserver.cpp` может выглядеть так:
332
333
``` c++
334
#include "foo/server/fooserver.hpp"
335
336
#include <sys/types.h>
337
#include <unistd.h>
338
339
#include <string>
340
#include <vector>
341
342
#include "base/basictypes.hpp"
343
#include "base/commandlineflags.hpp"
344
#include "foo/server/bar.hpp"
345
```
346
347
#### Исключения
348
349
Бывают случаи, когда требуется включение заголовочных файлов в зависимости от 
350
условий препроцессора (например, в зависимости от используемой ОС). Включение системно-зависимых файлов стоит
351
держать локализованным фрагментом после других заголовочных файлов. Например:
352
353
``` c++
354
#include "foo/public/fooserver.h"
355
356
#include "base/port.h"
357
358
// For LANG_CXX11.
359
#ifdef LANG_CXX11
360
#include <initializer_list>
361
#endif // LANG_CXX11
362
```
363
364
## Область видимости
365
366
### Пространства имен
367
368
Код, за некоторым исключением должен быть размещен в пространстве имен. 
369
Имена пространств имен должны быть уникальными и основываться на названии и, 
370
возможно, пути проекта. Не используйте *using-директивы* 
371
(`using namespace std`). Не используйте inline пространства имен. Для 
372
безымянных пространств имен см. 
373
[внутреннее связывание](#Внутреннее-связывание-Internal-Linkage).
374
375
*Пространства имен (namespaces)* разбивают глобальную область видимости на
376
несколько, отдельных и именованных. Это помогает предотвращать коллизии имен в 
377
глобальной области видимости. 
378
379
Пространства имен позволяют избегать конфликтов названий, при этом, большая 
380
часть кода использует короткие названия.
381
382
Например, представим себе, что два различных проекта имеют класс `Foo` в 
383
глобальной области видимости. Эти сущности могут столкнуться как во время 
384
компиляции, так и во время исполнения. Если код каждый проект будет помещен в 
385
свое пространство имен, то теперь `project1::Foo` и `project2::Foo` - это две 
386
отдельных сущности, и теперь коллизия не возникнет, при этом внутри проектов 
387
обращение к соответствующему классу `Foo` будет осуществляться без каких-либо 
388
префиксов.
389
390
Inline-пространства имен автоматически подставляют названия в окружающую область 
391
видимости. Например:
392
393
```c++
394
namespace outer {
395
inline namespace inner {
396
    void foo();
397
} // namespace inner
398
} // namespace outer
399
```
400
401
Выражения `outer::inner::foo()` и `outer::foo()` - взаимозаменяемы. 
402
Inline-пространства имён в основном используются для совместимости ABI между 
403
версиями.
404
405
Пространства имен могут запутать, поскольку они усложняют понимание того, какое
406
определение к какому названию относится.
407
408
Inline-пространства имен запутывают еще сильнее, поскольку название не 
409
ограничены своим пространством имен. Это просто полезная часть политики 
410
управления версиями.
411
412
В ряде случаев требуется использование полных имён, что может добавить в код 
413
беспорядка.
414
415
Пространства имен следует использовать следующим образом:
416
417
 * Следуйте [правилам](#Именование-пространства-имён-namespace) именования 
418
 пространств имен.
419
 * Завершайте пространства имен комментариями, как в примере ниже
420
 * Заключайте в пространство имён целиком файл с исходным кодом после 
421
 `#include`-ов, макросов, объявлений/определений `gflag`-ов и предварительных 
422
 объявлений классов из других пространств имён.
423
424
``` c++
425
// В .hpp файле
426
namespace mynamespace {
427
428
// Все объявления внутри блока пространства имён.
429
// Обратите внимание на отсутствие отступа.
430
class MyClass {
431
public:
432
...
433
void Foo();
434
};
435
} // namespace mynamespace
436
```
437
438
``` c++
439
// В .cpp файле
440
namespace mynamespace {
441
442
// Определение функций внутри блока пространства имён.
443
void MyClass::Foo() {
444
...
445
}
446
} // namespace mynamespace
447
```
448
 * Не объявляйте ничего в пространстве имен `std`. В том числе и предварительные
449
 объявления.
450
 * Не используйте директиву `using namespace ...;` - это загрязняет глобальное 
451
 пространство имен.
452
 * Не используйте using-объявление `using foo::Bar;` в заголовочных файлах.
453
 * Не используйте псевдонимы пространств имен в заголовочных файлах за 
454
 исключением явно внутренних пространств имен.
455
456
``` с++
457
// Укороченная запись для доступа к часто 
458
// используемым именам в .cpp файлах - Нормально
459
namespace baz = ::foo::bar::baz;
460
```
461
462
``` c++
463
// Укороченная запись для доступа к часто используемым именам (в .hpp файле).
464
namespace librarian {
465
namespace impl { // Внутреннее содержимое, не являющееся частью API.
466
namespace sidetable = ::pipeline_diagnostics::sidetable;
467
} // namespace impl
468
469
inline void my_inline_function() {
470
    // Пространство имён, локальное для функции (или метода).
471
    namespace baz = ::foo::bar::baz;
472
...
473
}
474
} // namespace librarian
475
```
476
 * Не используйте inline-пространства имен.
477
478
### Внутреннее связывание (Internal Linkage)
479
480
В том случае, если возможность ссылки на определения из `.cpp`-файла из других 
481
файлов должна быть запрещена, необходимо использовать внутреннее связывание. 
482
Для этого нужно либо объявить эти сущности как `static`, либо разместить их в 
483
безымянном пространстве имен (unnamed namespace). Не используйте внутреннее 
484
связывание в заголовочных файлах.
485
486
Форматирование безымянных пространств производится так же, как и именованных. 
487
В завершающем комментарии, название пространства имен должно быть оставлено 
488
пустым.
489
490
``` c++
491
namespace {
492
...
493
} // namespace
494
```
495
496
### Функции: глобальные, статические внутри и вне классов
497
498
Глобальные функции предпочтительно располагать в пространствах имен; используйте 
499
абсолютно глобальные функции как можно реже. Не используйте классы просто для 
500
того, чтобы сгруппировать статические члены. Статические методы класса должны 
501
быть сильно связаны с объектами данного класса или его статическими данными.
502
503
Глобальные и статические функции могут быть полезны в ряде случаев. Помещение
504
глобальных функций в пространство имен предотвращает загрязнение глобального 
505
пространства имен. 
506
507
Глобальные и статические функции могут стать понятнее при помещении в новый 
508
класс как функций-членов, особенно если они имеют доступ ко внешним ресурсам
509
или имеют явные зависимости.
510
511
Иногда полезно объявить функцию, не привязанную к объекту класса. Такие функции 
512
могут быть глобальными или статическими. Глобальная функция не должна иметь 
513
зависимостей от внешних переменных и практически всегда должна быть помещена
514
в пространство имен. Не создавайте класс для группировки таких функций.
515
Это ничем не отличается от обычного префикса и часто в этом нет смысла.
516
517
Если глобальная функция используется только в одном `.cpp`-файле, 
518
используйте [внутреннее связывание](#Внутреннее-связывание-Internal-Linkage).
519
520
### Локальные переменные
521
522
Располагайте локальные переменные функций в максимально узкой области видимости, 
523
инициализируйте эти переменные при объявлении. 
524
525
Язык C++ допускает объявление переменной в любом месте функции. Рекомендуется 
526
делать это в максимально локальной области видимости и максимально близко к 
527
месту первого использования. Так читателю будет проще найти объявление 
528
переменной и понять, каким значением она инициализирована. В частности 
529
инициализация более предпочтительна, чем объявление и присваивание. Например:
530
531
```c++
532
int i;
533
i = f(); // Плохо -- инициализация отделена от объявления.
534
535
int j = g(); // Хорошо -- объявление с инициализацией.
536
537
std::vector<int> v;
538
v.push_back(1); // Желательно инициализировать с помощью {}.
539
v.push_back(2);
540
541
std::vector<int> v = {1, 2}; // Хорошо -- v сразу инициализирован.
542
```
543
544
Переменные, необходимые для использования внутри конструкций `if`, `while`, 
545
`for`, следует объявлять внутри условий цикла. Тогда их область видимости будет
546
ограничена этими циклами:
547
548
```c++
549
while (const char* p = strchr(str, '/')) str = p + 1;
550
```
551
552
Существует тонкость: Если переменная - это объект, то его конструктор будет 
553
вызываться каждый раз при входе в область видимости, а деструктор - при выходе 
554
из нее. 
555
556
```c++
557
// Неэффективная реализация:
558
for (int i = 0; i < 1000000; ++i) {
559
    Foo f; // Конструктор и деструктор Foo вызовутся по 1000000 раз каждый.
560
    f.DoSomething(i);
561
}
562
```
563
564
Объявление такой переменной вне цикла может быть более эффективным:
565
566
```c++
567
Foo f; // Конструктор и деструктор Foo вызовутся по одному разу.
568
for (int i = 0; i < 1000000; ++i) {
569
    f.DoSomething(i);
570
}
571
```
572
573
### Статические и глобальные переменные
574
575
В статической области видимости (static storage duration) запрещены объекты, 
576
за исключением тривиально удаляемых (trivially destructible). Это значит, что 
577
деструктор такого объекта не должен делать ничего. Это же относится и к 
578
деструкторам базовых классов, поскольку они будут вызваны неявно. 
579
Более формально: тип не содержит пользовательского или виртуального деструктора,
580
а также все его члены и базовые типы являются тривиально-удаляемыми. Статические
581
переменные в функциях могут использовать динамическую инициализацию. 
582
Динамическая инициализация в статических переменных классов или глобальных 
583
переменных не приветствуется, но разрешена в некоторых случаях. Подробнее ниже.
584
585
_Хорошее правило:_ глобальная переменная удовлетворяет данным требованиям, 
586
если она может быть объявлена как `constexpr`.
587
588
У каждого объекта есть *время хранения (storage duration)*, которое соотносится 
589
с его временем жизни. Объекты со статическим временем хранения живут от точки 
590
инициализации и до конца работы программы. Такие объекты встречаются в качестве 
591
глобальных переменных, статических переменных классов и статических переменных 
592
функций. Все объекты со статическим временем хранения удаляются в фазе 
593
завершения программы (до обработки незавершённых потоков).
594
595
Инициализация может быть *динамической*, когда в конструкторе случается что-либо
596
нетривиальное, например выделение памяти, открытие файла, получение системных 
597
ресурсов. Другой вид инициализации - *статическая*. Одна инициализация не 
598
исключает другой: статическая инициализации выполняется в любом случае, 
599
затем, если необходимо, выполняется динамическая инициализация.
600
601
Глобальные и статические переменные очень полезны во многих применениях: 
602
именованные константы, внутренние дополнительные структуры данных, 
603
флаги командной строки, логирование, механизмы регистрации, организация 
604
внутренней инфраструктуры и т. д.
605
606
Глобальные и статические переменные, использующие динамическую инициализацию или
607
нетривиальные деструкторы могут легко привести к трудно обнаруживаемым багам. 
608
Порядок динамической инициализации и удаления между единицами трансляции 
609
не определен явно. Если один такой объект зависит от другого, то доступ к нему 
610
может осуществляться еще до того, как его время жизни началось или уже после 
611
того, как оно закончилось. Более того, когда приложение завершает потоки, 
612
они могут попытаться обратиться к уже удаленным или удаляемым объектам.
613
614
#### Ограничения по уничтожению
615
616
В случае с тривиальными деструкторами, их исполнение не зависит от порядка, 
617
поскольку, никакого "исполнения" деструкторов нет. В противном случае существует 
618
риск того, что доступ к объектам будет осуществляться после окончания их времени
619
жизни. По этой причине в статической области видимости разрешены только
620
тривиально-уничтожаемые объекты. Фундаментальные типы данных, такие как
621
указатели или `int` являются тривиально-уничтожаемыми, как и массивы
622
тривиально-уничтожаемых данных. Переменные, отмеченные как `constexpr` являются
623
тривиально-уничтожаемыми. 
624
625
```c++
626
const int kNum = 10; // Допустимо
627
628
struct X { int n; };
629
const X kX[] = {{1}, {2}, {3}}; // Допустимо
630
631
void foo() {
632
    static const char* const kMessages[] = {"hello", "world"}; // Допустимо
633
}
634
635
// Допустимо: constexpr всегда имеет тривиальный деструктор
636
constexpr std::array<int, 3> kArray = {{1, 2, 3}}
637
```
638
639
```c++
640
// Плохо: нетривиальный деструктор
641
const std::string kFoo = "foo";
642
643
// Плохо по тем же причинам (хотя kBar и является ссылкой, но 
644
// правило применяется и для временных объектов в расширенным временем жизни)
645
const std::string& kBar = StrCat("a", "b", "c");
646
647
void bar() {
648
    // Плохо: нетривиальный деструктор
649
    static std::map<int, int> kData = {{1, 0}, {2, 0}, {3, 0}};
650
}
651
```
652
653
_На заметку_ : ссылки не являются объектами, и на них не распространяются 
654
ограничения по уничтожению. Ограничения по инициализации все еще остаются. 
655
В частности, статическая ссылка в функции `static T& t = *new T` - разрешена.
656
657
#### Ограничения по инициализации
658
659
Инициализация - это более сложная тема, поскольку необходимо учитывать не только
660
выполнение конструктора класса, но и исполнения инициализации:
661
662
```c++
663
int n = 5;   // Отлично
664
int m = f(); // ? (Зависит от f)
665
Foo x;       // ? (Зависит от Foo::Foo)
666
Bar y = g(); // ? (Зависит от g и Bar::Bar)
667
```
668
669
Порядок инициализации для всех выражений, кроме первого, не определен.
670
671
Необходимо использовать концепцию, которая в стандарте C++ называется 
672
*константной* *инициализацией (constant initialization)*. Это значит, что 
673
выражение инициализации является *константным выражением (constant expression)*,
674
и если объект инициализируется вызовом конструктора, то конструктор должен быть 
675
объявлен как `constexpr`:
676
677
```c++
678
struct Foo { constexpr Foo(int) {} };
679
680
int n = 5;  // Отлично, 5 - константное выражение
681
682
Foo x(2);   // Отлично, 2 - константное выражение 
683
            // и вызывается constexpr конструктор
684
685
Foo a[] = { Foo(1), Foo(2), Foo(3) }; // Отлично
686
```
687
688
Константная инициализация всегда разрешена. Все нелокальные статические
689
переменные, конструкторы которых не помечены как `constexpr` должны 
690
восприниматься как динамически инициализируемые и тщательно проверяться.
691
692
Обратите внимание на следующие примеры:
693
694
```c++
695
// Объявления, используемые ниже
696
time_t time(time_t*);   // не constexpr !
697
int f();                // не constexpr !
698
struct Bar { Bar() {} };
699
700
// Проблемные инициализации
701
time_t m = time(nullptr);   // Выражение инициализации не константное
702
Foo y(f());                 // Те же проблемы
703
Bar b;                      // Конструктор Bar::Bar() не является constexpr
704
```
705
706
Динамическая инициализация переменных вне функций не рекомендуется. В общем 
707
случае это запрещено, однако, это можно делать если остальной код программы не 
708
зависит от порядка инициализации этой переменной. В этом случае изменение
709
порядка инициализации не может что-то изменить.
710
Например:
711
712
```c++
713
int p = getpid(); // Допустимо, пока другие статические переменные
714
                  // не используют p в своей инициализации
715
```
716
717
Динамическая инициализация статических локальных переменных функций допустима и
718
является широко распространённой практикой.
719
720
#### Рекомендуемые практики
721
 * Глобальные строки: Если требуется именованная глобальная или статическая 
722
 строковая переменная, используйте `constexpr string_view`, массив символов или 
723
 указатель, указывающий на строковый литерал.
724
 * Динамические контейнеры (`map`, `set` и т.д.): если требуется статическая
725
 коллекция с фиксированными данными (например, таблицы значений для поиска), то
726
 не используйте динамические контейнеры из стандартной библиотеки как тип для 
727
 статической переменной, т.к. у этих контейнеров нетривиальный деструктор. 
728
 Вместо этого попробуйте использовать массивы простых (тривиальных) типов, 
729
 например массив из массивов целых чисел (вместо `std::map<int, int>`) или, 
730
 например, массив структур с полями `int` и `const char*`. Учтите, что для
731
 небольших коллекций линейный поиск обычно вполне приемлем (и может быть очень 
732
 эффективным благодаря компактному размещению в памяти). Также можете 
733
 воспользоваться алгоритмами `absl/algorithm/container.h` для стандартных 
734
 операций. Также возможно создавать коллекцию данных уже отсортированной и 
735
 использовать алгоритм бинарного поиска. Если без динамического контейнера не 
736
 обойтись, то попробуйте использовать статическую переменную-указатель, 
737
 объявленную в функции (см. ниже).
738
 * Умные указатели (`unique_ptr`, `shared_ptr`): умные указатели освобождают 
739
 ресурсы в деструкторе и поэтому их нельзя использовать в качестве статических 
740
 или глобальных. Попробуйте применить другие практики/способы, описанные в 
741
 разделе. Например, одно из простых решений это использовать обычный указатель 
742
 на динамически выделенный объект и далее  никогда не удалять его 
743
 (см. последний вариант списка).
744
 * Статические переменные пользовательских типов: если необходима константа 
745
 типа, определённого вами, определяйте конструктор как `constexpr`, а 
746
 деструктор - тривиальным.
747
 * На крайний случай - создайте статический объект в функции динамически и 
748
 никогда его не удаляйте. (Например, 
749
 `static const auto& impl = new T(args...);`).
750
751
### thread_local-переменные
752
753
`thread_local`-переменные, которые объявлены вне функций должны 
754
инициализироваться константами времени компиляции(*true compile-time*). 
755
Используйте атрибут `ABSL_CONST_INIT` для того, чтобы в этом убедиться. 
756
Использование `thread_local` - это предпочтительный способ объявить данные 
757
внутрипотоковыми.
758
759
Начиная с C++11 переменные можно объявлять со спецификатором `thread_local`:
760
761
``` c++
762
thread_local Foo foo = ...;
763
```
764
765
Каждая такая переменная представляется собой коллекцию объектов. Каждый поток 
766
работает со своим экземпляром переменной. По поведению `thread_local`-переменные
767
во многом похожи на 
768
[статические переменные](#Статические-и-глобальные-переменные). Например, они 
769
могут быть объявлены в пространстве имён, внутри функций, как статические члены 
770
класса, но не как обычные члены класса.
771
772
Инициализация потоковых переменных очень напоминает статические переменные, 
773
за исключением что это делается для каждого потока. В том числе это означает, 
774
что объявлять `thread_local`-переменные внутри функции - безопасно, 
775
но остальные `thread_local`-переменные подвержены тем же проблемам, что и 
776
статические переменные.
777
778
Переменная `thread_local` не уничтожается до завершения потока, так что здесь 
779
нет проблем с порядком разрушения, как у статических переменных.
780
781
 * `thread_local`-переменные защищены от гонок, поскольку только один поток 
782
 имеет к ним доступ, что делает их использование полезным в многопоточных 
783
 приложениях;
784
 * `thread_local`-переменные - это единственный стандартный способ объявить 
785
 данные внутрипоточными.
786
 * Доступ к таким данным может спровоцировать исполнение непредсказуемого и 
787
 неконтролируемого количества кода.
788
 * По сути, `thread_local`-переменные являются глобальными со всеми вытекающими 
789
 недостатками.
790
 * Количество памяти, выделяемое для `thread_local`-переменных зависит от 
791
 количества запущенных потоков, что может быть чрезмерно большим.
792
 * `thread_local`-переменные могут менее эффективны, чем встроенные 
793
 (*compiler intrinsic*) функции компилятора.
794
795
Размещение `thread_local`-переменных внутри функции не влечет проблем с 
796
безопасностью, так что их можно использовать без ограничений. Можно использовать
797
такие переменные для организации глобального или статического доступа к данным, 
798
например:
799
800
```c++
801
Foo& MyThreadLocalFoo() {
802
    thread_local Foo result = ComplicatedInitialization();
803
    return result;
804
}
805
```
806
807
В области видимости класса или глобальной `thread_local`-переменных должны 
808
инициализироваться константами времени компиляции. Для того, чтобы это 
809
гарантировать используйте макрос `ABSL_CONST_INIT` или `constexpr`, но реже.
810
811
```c++
812
ABSL_CONST_INIT thread_local Foo foo = ...;
813
```
814
815
Используйте `thread_local` для объявления внутрипотоковых данных.
816
817
## Классы
818
819
Класс - это фундаментальная единица кода на C++. Обычно они используются очень 
820
широко. Данный раздел описывает все рекомендации, которым необходимо следовать 
821
при разработке классов.
822
823
### Выполнение задач в конструкторах
824
825
Избегайте вызовов виртуальных методов в конструкторах. Избегайте кода, который 
826
может завершиться ошибкой, если не будет способа о ней сообщить.
827
828
В конструкторе возможно выполнить любую инициализацию.
829
830
 * Нет необходимости заботиться о том, инициализирован объект класса или нет.
831
 * Объекты, которые целиком инициализируются в конструкторе могут быть 
832
константами. Также их проще использовать в контейнерах.
833
834
---
835
836
 * Если вызываются виртуальные функции, то не будут вызваны переопределения 
837
классов-наследников.
838
 * Нет простого способа сообщить об ошибке в конструкторе без аварийного
839
 завершения  программы.
840
или использования исключений.
841
 * Если инициализация провалилась, мы имеем объект в непонятном состоянии
842
 * Невозможно взять от конструктора адрес, поэтому возникают сложности с 
843
передачей конструктора в другой поток.
844
845
_Вывод:_
846
Конструкторы никогда не должны вызывать виртуальные функции. Используйте 
847
`init`-методы только в случае, если у объекта есть флаги состояния, разрешающие
848
вызывать те или иные публичные функции (т.к. сложно полноценно работать с 
849
частично сконструированным объектом).
850
851
### Неявное преобразование типов
852
853
Не используйте неявное преобразование типов. Используйте ключевое слово 
854
`explicit` для операторов преобразования типов или конструкторов с одним 
855
аргументом.
856
857
Неявное преобразование разрешает использование объектов одного типа там, 
858
где требуется использование объектов другого типа.
859
860
Программист может добавить свои механизмы для неявного преобразования типов 
861
путем добавления соответствующих членов в определение класса. Неявное 
862
преобразование в исходном типе может быть добавлено с помощью операторов 
863
преобразования типов, например `operator bool()`. Неявное преобразование в 
864
целевом типе реализуется при помощи конструктора с единственным аргументом 
865
исходного типа.
866
867
Ключевое слово `explicit` может быть применено к конструктору или оператору 
868
приведения типов, чтобы гарантировать, что неявное преобразование типов не 
869
будет работать. Это применимо не только к неявному преобразованию, но и к 
870
спискам инициализации. Например:
871
872
```c++
873
class Foo {
874
    explicit Foo(int x, double y);
875
    ...
876
};
877
878
void Func(Foo f);
879
880
Func({42, 3.14}); // Ошибка
881
```
882
883
Данный код не является примером неявного преобразования типов, но компилятор 
884
считает это таковым при использовании ключевого слова `explicit`.
885
886
 * Неявное преобразование может сделать тип удобнее или более выразительным 
887
 путем избавления от необходимости явно указывать целевой тип, когда это 
888
 очевидно.
889
 * Неявное преобразование может быть более простой альтернативой перегрузке 
890
 функций, например, если функция принимает параметр типа `string_view`, она 
891
 может принимать параметры типов `std::string` и `const char*`. 
892
 * Списки инициализации - это компактный и выразительный способ инициализации 
893
 объектов.
894
895
---
896
897
 * Использование списков инициализации могут скрыть ошибки несоответствия типов.
898
 * Неявное преобразование может сделать код более сложным для чтения, особенно
899
 когда также присутствуют и виртуальные функции.
900
 * Конструкторы с одним аргументом могут быть случайно использованы для 
901
 приведения типов, даже если это не предполагалось.
902
 * Не всегда очевидно, к какому типу данных должно выполняться приведение, 
903
 особенно в том случае, если несколько типов обеспечивают неявное преобразование.
904
 * Списки инициализации могут испытывать те же проблемы, особенно в случае, если 
905
 в списке один единственный элемент.
906
907
_Вывод:_
908
Операторы преобразования типов и конструкторы с одним элементом должны быть 
909
объявлены как `explicit` в определении классов. Конструкторы копирования и 
910
перемещения не должны быть `explicit`, поскольку они не осуществляют приведение 
911
типов. 
912
913
Неявное преобразование типов может иногда быть необходимы для типов, которые 
914
должны быть взаимозаменяемыми. Подобные вопросы должны быть согласованы с
915
 начальством.
916
917
Конструкторы с несколькими параметрами могут не использовать `explicit`. 
918
Конструкторы, которые используют один параметр `std::initializer_list` 
919
не должны использовать `explicit` для поддержки инициализации присваиванием 
920
`MyType m = {1, 2};`.
921
922
### Копируемые и перемещаемые типы данных
923
924
В публичном API класса должно быть явно указано, является ли класс копируемым,
925
перемещаемым, или ни тем, ни другим. Поддержка копирования или перемещения 
926
должна осуществляться, если она имеет смысл для этого типа данных.
927
928
*Перемещаемый (movable)* тип может быть инициализирован временным объектом или 
929
ему может быть присвоен временный объект.
930
931
*Копируемый (copyable)* тип может быть инициализирован другим объектом такого же
932
типа или присвоен ему с оговоркой, что исходный объект не должен изменяться. Тип
933
`std::unique_ptr`, например, является перемещаемым, но не копируемым. Типы 
934
данных `int` или `std::string` - это примеры типов данных, которые являются
935
перемещаемыми и копируемыми. 
936
937
Для пользовательских типов данных поведение при копировании определяется в 
938
*конструкторе копирования (copy constructor)* и в 
939
*операторе присваивания с копированием (copy-assignment operator)*. 
940
Поведение при перемещении определяется в 
941
*конструкторе перемещения (move constructor)* и в 
942
*операторе присваивания с перемещением (move-assignment operator)*, если они 
943
присутствуют, либо поведением при копировании в противном случае.
944
945
Конструкторы копирования/перемещения могут быть вызваны компилятором неявно. 
946
Например, в случае передачи в функцию по значению.
947
948
Объекты копируемых и перемещаемых типов могут быть переданы и возвращены по 
949
значению, что делает API проще, безопаснее и универсальнее. В отличие от 
950
передачи объектов через указатель или ссылку, нет риска запутаться с временем 
951
жизни, владением, изменчивостью и подобными рисками. Также это предотвращает 
952
нелокальное взаимодействие между клиентом и реализацией API, что существенно 
953
упрощает понимание, поддержку кода, а также его оптимизацию компилятором. Такие 
954
объекты  можно использовать с любым API, для которого необходима передача по 
955
значению. Например, контейнеры.
956
957
Конструкторы копирования/перемещения и операторы присваивания проще в 
958
определении, чем специальные функции, по типу `Clone()`, `CopyFrom()`, `Swap()`, 
959
потому что они могут быть сгенерированы компилятором, в том числе, неявно. Они 
960
более эффективны, поскольку не требуют выделения памяти на куче, дополнительных 
961
присвоений и хорошо оптимизируются.
962
963
Операции перемещения позволяют неявно и эффективно управлять передачей ресурсов 
964
через rvalue-объекты. Это позволяет делать код проще.
965
966
Некоторым типам не требуется быть копируемыми, а предоставление операций 
967
копирования для таких типов может быть запутанным, нелогичным или неверно 
968
понятым. Синглтоны, объекты, привязанные к специфической области видимости 
969
(например, `Cleanup`) или сильно связанные с уникальными данными, например 
970
(`Mutex`), не могут быть копируемыми по своему смыслу. Операции копирования для 
971
базовых классов, имеющих наследников, может перевести к *object slicing*'у - 
972
когда свойства из базового класса копируются, а свойства из производного - нет.
973
974
Конструкторы копирования вызываются неявно, поэтому их выполнение легко упустить 
975
из виду. Это может привести, например, к снижению производительности из-за 
976
лишнего копирования данных.
977
978
Интерфейс каждого класса должен явно определять, какие операции копирования или 
979
перемещения класс поддерживает. Это достигается путем явного объявления или 
980
удаления (с помощью ключевого слова `delete`) соответствующих операторов в 
981
секции `public`. 
982
983
В частности, копируемые классы должны явно объявлять операции копирования, а 
984
перемещаемые - операции перемещения. В некопируемыех и неперемещаемых классах 
985
соответствующие операторы должны быть явным образом удалены. Копируемый класс 
986
может также объявить операторы перемещения для поддержки более эффективного 
987
способа передачи данных. При объявлении оператора присваивания копирования или 
988
перемещения должен быть реализован соответствующий конструктор.
989
990
```c++
991
class Copyable {
992
public:
993
    Copyable(const Copyable& other) = default;
994
    Copyable& operator=(const Copyable& other) = default;
995
996
    // Неявное определение операций перемещения будет запрещено 
997
    // (т.к. объявлено копирование).
998
    // Можно определить соответствующие операции явно.
999
};
1000
1001
class MoveOnly {
1002
public:
1003
    MoveOnly(MoveOnly&& other);
1004
    MoveOnly& operator=(MoveOnly&& other);
1005
1006
    // Неявно определённые операции копирования удаляются. 
1007
    // Но (если хотите) можно это записать
1008
    MoveOnly(const MoveOnly&) = delete;
1009
    MoveOnly& operator=(const MoveOnly&) = delete;
1010
};
1011
1012
class NotCopyableOrMovable {
1013
public:
1014
    // Такое объявление запрещает и копирование и перемещение
1015
    NotCopyableOrMovable(const NotCopyableOrMovable&) = delete;
1016
    NotCopyableOrMovable& operator=(const NotCopyableOrMovable&) = delete;
1017
1018
    // Хотя операции перемещения запрещены (неявно), можно записать это явно:
1019
    NotCopyableOrMovable(NotCopyableOrMovable&&) = delete;
1020
    NotCopyableOrMovable& operator=(NotCopyableOrMovable&&) = delete;
1021
};
1022
```
1023
1024
Описываемые объявления или удаления функций можно опустить в очевидных случаях:
1025
1026
 * Если класс не содержит секции `private` например, структура или 
1027
 класс-интерфейс, то копируемость и перемещаемость определяется копируемостью и
1028
 перемещаемостью всех открытых членов.
1029
 * Если базовый класс явно некопируемый и неперемещаемый, наследные классы будут
1030
 такими же. Однако, если базовый класс не объявляет это операции, то этого будет
1031
 недостаточно для прояснения свойств наследуемых классов.
1032
 * _На заметку:_ Если конструктор копирования или оператор присваивания 
1033
 объявлен/удалён, то нужно и явно объявить/удалить оператор копирования, 
1034
 поскольку его статус неочевиден. Аналогично и для операций перемещения.
1035
1036
Тип не должен быть копируемым/перемещаемым, если смысл данных операций 
1037
неочевиден пользователю, или если его реализация влечет к большим затратам. 
1038
Операции перемещения для копируемых типов нужны только для оптимизации 
1039
производительности и являются потенциальным источником ошибок. Определяйте их 
1040
только в том случае, если их использование значительно более эффективно, чем 
1041
использование операций копирования. Желательно, чтобы для копирования и 
1042
перемещения использовались функции по-умолчанию. Если они используются - 
1043
обязательно проверьте, что они работают корректно.
1044
1045
Из-за риска слайсинга стоит избегать открытых операторов копирования и 
1046
перемещения для классов, которые планируется использовать в качестве базовых, и 
1047
не наследовать классы от классов с оператором присваивания. Старайтесь 
1048
наследовать свои классы только от *чистых абстрактных (pure abstract)*.
1049
1050
### Структуры против классов
1051
1052
Используйте структуры только для пассивных объектов, предназначенных для 
1053
хранения данных. Во всех остальных случаях используйте классы.
1054
1055
Ключевые слова `struct` и `class` в языке C++ практически идентичны, но мы 
1056
вводим дополнительную семантику для этих ключевых слов. 
1057
1058
Структуры должны использоваться для пассивных объектов, предназначенных для 
1059
хранения данных. Структуры могут иметь константы. Структуры не должны содержать
1060
инварианты, которые характеризуют отношения между полями, поскольку прямой 
1061
доступ к полям может их нарушить. Могут присутствовать конструкторы, 
1062
деструкторы и методы-помощники, но они не должны создавать инвариантов.
1063
1064
Если сомневаетесь, используйте `class`.
1065
1066
Для единообразия с STL для `stateless`-типов можно использовать `struct`.
1067
Например, `type_traits` и некоторые функторы.
1068
1069
Не забывайте о том, что у структур и классов разные 
1070
[правила об именовании](#Имена-переменных).
1071
1072
### Структуры против пар и кортежей
1073
1074
Когда элементы в наборе могут иметь содержательные названия, использование 
1075
структур является более предпочтительным, чем кортежи или пары.
1076
1077
Хотя использование кортежей и пар позволяет избежать создания пользовательского 
1078
типа для хранения набора разнотипных данных, доступ к элементам структуры с 
1079
осмысленными названиями лучше *читается*, чем `std::get<X>` или 
1080
`.first`, `.second`. Хотя C++14 позволяет обращаться к элементам кортежа по 
1081
типу, если он уникален, поля структур намного более информативны.
1082
1083
Пары и кортежи имеет смысл использовать там, где нет больших различий между 
1084
полями кортежа или для работ с существующим кодом или API.
1085
1086
### Наследование
1087
1088
*Композиция* часто предпочтительнее наследования. Когда используете наследование, 
1089
делайте его открытым (`public`). 
1090
1091
Когда подкласс наследуется от базового класса, он включает все определения всех 
1092
данных и операций, определенных в базовом классе. 
1093
*Наследованием интерфейса (Interface Inheritance)* будем называть наследование 
1094
от *чистого абстрактного базового класса (pure abstract base class)* (без 
1095
определенных функций и состояния). Любое другое наследование будем называть 
1096
*Наследованием реализации (implementation inheritance)*.
1097
1098
*Наследование реализации* уменьшает размер кода путем повторного использования 
1099
кода базового класса путем специализации существующего типа. Поскольку 
1100
наследование выполняется в процессе компиляции, программист и компилятор могут 
1101
понять операции и обнаружить ошибки. *Наследование интерфейса* может быть 
1102
использовано глобально для того, чтобы программно гарантировать, что класс 
1103
экспортирует определенный API. Опять же, в данном случае компилятор может в 
1104
данном случае обнаружить ошибки в том случае, если класс не определяет нужный 
1105
метод API.
1106
1107
Код, использующий *наследование реализации* становится менее понятным, 
1108
поскольку реализация методов размазывается между базовым и дочерними классами. 
1109
Дочерний класс не может переопределить невиртуальные функции.
1110
1111
Множественное наследование особенно проблематично, поскольку часто влечет за
1112
собой большие накладные расходы по производительности и риски ромбовидного 
1113
наследования (*diamond inheritance*), которое может повлечь за собой баги, 
1114
неопределенность и путаницу.
1115
1116
Любое наследование должно быть открытым (*public*). Если у вас возникает 
1117
потребность в закрытом наследовании, то необходимо создать закрытый член класса 
1118
который вы хотите сделать базовым. Можно использовать ключевое слово `final` на 
1119
классах, наследование от которых должно быть запрещено.
1120
1121
Не злоупотребляйте *наследованием реализации*. Композиция часто является более 
1122
предпочтительной. Используйте семантику *является*. Класс `Bar` стоит 
1123
наследовать от `Foo`, если можно дать утвердительный ответ на вопрос `Bar` 
1124
является `Foo`?
1125
1126
Ограничьте использование защищенных (`protected`) функций, которые должны быть 
1127
доступны подклассам. Помните, [данные должны быть закрытыми](#Контроль-доступа) 
1128
(`private`).
1129
1130
Множественное наследование разрешено, но множественное *наследование реализации* 
1131
не рекомендуется.
1132
1133
### Перегрузка операторов
1134
1135
Перегружайте операторы в рамках разумного. Не используйте пользовательские 
1136
литералы.
1137
1138
С++ позволяет программисту определять своим версии встроенных операторов, 
1139
используя для этого ключевое слово `operator` и пользовательский тип, 
1140
как один из параметров. Также ключевое слово `operator` позволяет создавать 
1141
пользовательские литералы, используя `operator""` и операторы приведения типов, 
1142
например `operator bool()`. Это называется *перегрузкой операторов*.
1143
1144
Использование перегрузки операторов может сделать код более выразительным и 
1145
интуитивным, когда пользовательские типы ведут себя как встроенные. 
1146
Перегружаемые операторы соответствуют определенным операциям и следование логике 
1147
применения этой операции может сделать работу с пользовательскими типами более 
1148
читаемой, а также использовать их при работе с библиотеками, которые используют 
1149
данные операторы.
1150
1151
Пользовательские литералы - это выразительный способ создания объектов 
1152
пользовательских типов.
1153
1154
 * Предоставление корректного, согласованного и логичного набора операторов для 
1155
 пользовательского типа требует усилий и может обернуться запутыванием и багами.
1156
 * Злоупотребление перегрузкой операторов может привести к непонятному коду, 
1157
 особенно, если эти семантика данных операторов не соответствует общепринятой.
1158
  * Все проблемы, связанные с перегрузкой функций распространяются и на 
1159
  перегрузку операторов.
1160
 * Перегрузка операторов может быть не интуитивной в плане производительности, 
1161
 поскольку встроенные операции очень производительны.
1162
 * Поиск в коде вызовов перегруженных операций требует особых утилит поиска, 
1163
 понимающих синтаксис C++.
1164
 * Если запутаться с типами операндов перегружаемых операций, можно получить 
1165
 другой перегруженный оператор, а не ошибку компиляции, например `foo < bar` и 
1166
 `&foo < &bar`.
1167
 * Перегрузка некоторых операторов является раскованной сама по себе. Например, 
1168
 перегрузка унарного `&`. Перегрузка операторов `&&`, `||`, `,` не порядку 
1169
 исполнения встроенных операций.
1170
 * Операторы могут определяться вне класса, поэтому есть риск того, что разные 
1171
 файлы могут содержать разное определение одного и того же оператора. Это может 
1172
 привести к трудноуловимым ошибкам времени исполнения.
1173
 * Пользовательские литералы создают новые синтаксические формы, которые будут 
1174
 незнакомы даже продвинутым программистам. Например: `"Hello World"sv` как 
1175
 сокращение для `std::string_view(«Hello World»)`. 
1176
 * Т. к. для пользовательских литералов не указывается пространство имен, 
1177
 придется использовать либо using-директиву, 
1178
 [которая запрещена](#Пространства-Имен), либо using-объявление, запрещенное в 
1179
 заголовочных файлах. 
1180
1181
_Выводы:_
1182
1183
Используйте перегрузку операторов только тогда, когда их значение очевидно, 
1184
предсказуемо и согласовано со встроенными операциями. Например, переопределяйте 
1185
оператор `|` как логическое `ИЛИ`, а не как перенаправление потока. 
1186
1187
Перегружайте операторы только для своих типов данных. Определяйте их в той же 
1188
паре `.hpp`/`.cpp` - файлов, что и тип данных, к которому они относятся. Таким 
1189
образом операции будут доступны тогда же, когда и исходный тип данных, а риск 
1190
нескольких определений операторов будет минимизирован. По возможности избегайте 
1191
определения шаблонных (`template`) операторов, поскольку они должны 
1192
соответствовать определенным правилам для всех аргументов. При перегрузке 
1193
операторов, перегружайте все связанные операторы, например, при перегрузке 
1194
оператора `<`, необходимо перегрузить все операторы сравнения. Убедитесь, что 
1195
они работают согласовано. Например, что операторы `<` и `>` 
1196
никогда не возвращают `true` одновременно.
1197
1198
По возможности, не делайте перегруженные операторы функциями-членами классов. 
1199
Если бинарный операнд определен как член класса, риски неявного преобразования 
1200
существуют только для правого оператора, а если как глобальная функция - для 
1201
обоих. Будет странно, если `a < b` компилируется, а `b > a` - нет.
1202
1203
Не заходите слишком далеко, избегая перегрузки операторов. Перегрузка 
1204
операторов предпочтительнее, чем функции, по типу 
1205
`equals(), copyFrom(), printTo()`. И наоборот, не перегружайте оператор только 
1206
из-за того, что он нужен какой-то библиотеке. Например, если вы хотите 
1207
использовать `std::set` для типа, для которого не предусмотрено логикой 
1208
операций больше или меньше, используйте свою функцию-компаратор вместо 
1209
перегрузки оператора `<`.
1210
1211
Не перегружайте операторы `&&, ||, ,(запятая)` и унарный `&`. 
1212
Не используйте пользовательские литералы. 
1213
1214
Операторы преобразования типов обсуждаются и в секции про 
1215
[неявное преобразование типов](#неявное-преобразование-типов). 
1216
Оператор `=` затрагивается в секции про 
1217
[конструкторы копирования](#копируемые-и-перемещаемые-типы-данных). 
1218
Перегрузка оператора `<<` затрагивается в секции про 
1219
[потоки](#потоки-ввода-вывода). Также обратите внимание не секцию про
1220
[перегрузку функций](#перегрузка-функций), которая затрагивает перегрузку в 
1221
целом.
1222
1223
### Контроль доступа
1224
1225
Члены-данные класса должны быть закрытыми (`private`), если это не константы 
1226
(`const`). Это упрощает работу с инвариантами ценой создания простых 
1227
клишированных функций (get/set-ассессоров), если не обходимо.
1228
1229
По техническим причинам члены данных фикстур для Google Test могут быть 
1230
`protected`.
1231
1232
### Порядок объявления
1233
1234
Группируйте похожие объявления.
1235
1236
Определение класса обычно начинается с секции `public:`, за которой следует 
1237
`protected:`, а в конце - `private:`. Избегайте пустых секций.
1238
1239
Внутри каждой секции группируйте похожие виды объявлений вместе. 
1240
Предпочтительным является такой порядок:
1241
1242
 1. Типы данных и псевдонимы (`typedef`, `using`, `enum`, вложенные 
1243
 структуры и классы, `friend`-типы данных).
1244
 2. Статические константны.
1245
 3. Фабричные методы
1246
 4. Конструкторы и операторы присваивания
1247
 5. Деструктор
1248
 6. Все остальные функции (статические и нестатические функции-члены, 
1249
 дружественные функции).
1250
 7. Свойства класса (Члены-данные) (статические и нет).
1251
1252
Не размещайте определения больших методов внутри классов. Обычно только 
1253
тривиальные или критичные к производительности функции могут быть определены 
1254
как `inline`. См. [здесь](#inline-функции).
1255
1256
## Функции
1257
1258
### Входные и выходные данные
1259
1260
Как правило, выходные данные функции предоставляются через возвращаемое 
1261
значение, иногда через выходные (или входные-выходные) параметры.
1262
1263
Использование возвращаемых значений предпочтительнее, поскольку они улучшают 
1264
читаемость, при этом часто демонстрируя такую же или лучшую производительность.
1265
1266
Возвращение значения предпочтительно, если не получается, используйте 
1267
возвращение по ссылке. Избегайте использования возвращения по указателю, 
1268
если тот не может быть `null`.
1269
1270
Параметры функций могут быть входными, выходными или и теми, и другими. 
1271
Обязательные входные параметры, как правило, передаются по значению или 
1272
константной ссылке. Выходные параметры должны передаваться по неконстантной
1273
ссылке, если они не могут быть `null`. В общем случае, используйте 
1274
`std::optional` для необязательных входных параметров и константный указатель, 
1275
если обязательный параметр был бы ссылкой (поскольку он `nullable`). 
1276
Используйте неконстантные указателя для необязательных выходных или 
1277
входных-выходных параметров.
1278
1279
Избегайте использований константных ссылок **только** для того, чтобы продлить
1280
время жизни временных объектов (константные ссылки могут расширять время жизни 
1281
и могут быть привязаны к временным объектам). Вместо этого постарайтесь найти 
1282
способ избавиться от требований к времени жизни путем копирования объекта или 
1283
используйте указатель, задокументировав время жизни и требования к тому, чтобы 
1284
он не был `null`.
1285
1286
При объявлении параметров функции старайтесь сначала объявлять входные 
1287
параметры функций, а потом выходные. Это не жесткое правило.
1288
1289
### Пишите короткие функции
1290
1291
Пишите короткие и концентрированные функции.
1292
1293
> *Функция должна делать одну вещь и делать ее хорошо!* - (c) Дядя Боб.
1294
1295
Иногда длинная функция бывает полезной, но если размер функции превышает 40 
1296
строк - это повод задуматься над тем, чтобы разбить ее на несколько.
1297
1298
Длинные функции тяжело читаются и сложнее отлаживаются. С длинными функциями 
1299
сложнее работать в команде, поскольку будут возникать проблемы при слиянии. 
1300
Короткие функции легче тестировать.
1301
1302
При работе со старыми функциями, которые кажутся слишком длинными и запутанными, 
1303
не бойтесь ее модифицировать: если работа с такой функцией затруднена или 
1304
неудобна, если в ней есть ошибки, которые трудно отлаживать или если кусочки 
1305
данной функции можно применить в другом месте, не бойтесь разбивать ее на 
1306
меньшие и более управляемые куски.
1307
1308
Как правило, функция должна иметь не более 3х параметров. Особенно, если она 
1309
экспортируется из API. Существуют исключения, например, когда функцию совершенно 
1310
необходимо сделать `stateless`, но это "дурно пахнет".
1311
1312
### Перегрузка функций
1313
1314
Используйте перегрузку функций (в т. ч., конструкторов) только если читатель, 
1315
смотря на код ее вызова будет хорошо понимать, что происходит без точного 
1316
определения, какая именно перегрузка вызывается. 
1317
1318
Например, можно написать функцию, которая принимает аргумент 
1319
`const std::string&` и перегрузить другой функцией, которая принимает 
1320
`const char*`. Так или иначе, в данном случае лучше использовать 
1321
`std::string_view`. 
1322
1323
```c++
1324
class MyClass {
1325
public:
1326
    void Analyze(const std::string &text);
1327
    void Analyze(const char *text, size_t textlen);
1328
};
1329
```
1330
1331
Перегрузка функций может быть более интуитивной, позволяя иметь функции с одним
1332
названием, применяя разные аргументы. Это может быть необходимо для шаблонного 
1333
кода и это удобно для реализации паттерна `Visitor`. 
1334
1335
Перегрузка, основанная на использовании квалификаторов `const` или `&` может 
1336
сделать кода более удобным и эффективным.
1337
1338
Пользователь должен хорошо знать правила C++ по подстановке типов, если функция 
1339
перегружается только по типу аргументов, а не по количеству. Также перегрузка 
1340
может быть запутанной, а также при наследовании, если класс-наследник 
1341
переопределяет одну виртуальную функцию, но не переопределяет перегруженную.
1342
1343
_Вывод:_
1344
Перегружайте функцию только тогда, когда нет семантической разницы между 
1345
перегруженными вариантами. Перегруженные операторы могут отличаться по типам, 
1346
квалификаторам, и количеству аргументов. Пользователь не должен разбираться, 
1347
какая конкретно перегрузка была вызвана, только то, что была вызвана какая-то 
1348
реализация из множества была вызвана. 
1349
1350
> Если вы можете задокументировать все 
1351
> перегрузки одним комментарием в заголовочном файле, это хороший знак, 
1352
> что данное множество перегруженных функций было спроектировано хорошо.
1353
1354
### Аргументы по-умолчанию
1355
1356
Аргументы по-умолчанию разрешены в невиртуальных функциях и тогда, когда 
1357
аргумент по-умолчанию всегда имеет одно и тоже значение. Следуйте тем же 
1358
ограничениям, что и при [перегрузке](#перегрузка-функций). Перегрузка функций 
1359
предпочтительнее, чем аргументы по-умолчанию в тех случаях, когда преимущество 
1360
по читаемости аргументы по-умолчанию не перевешивает их недостатков.
1361
1362
Часто бывает так, что у вас есть функция, использующая какие-то значения, но 
1363
*иногда* для них необходимо переопределить. Используя аргументы по-умолчанию, 
1364
это можно сделать без объявления нескольких функций для редких исключений. В 
1365
сравнении с перегрузкой функций, синтаксис аргументов по-умолчанию чище, 
1366
с меньшим количеством нефункционального кода и явным отделением "обязательных" 
1367
аргументов от "необязательных".
1368
1369
Аргументы по-умолчанию - это еще один способ добиться семантики, похожей на 
1370
перегрузку функций. Поэтому причины [не делать функции перегруженными]
1371
(#перегрузка-функций) распространяются и на них.
1372
1373
В случае с виртуальными функциями значение аргумента по-умолчанию определяется 
1374
статическим типом целевого объекта и нет никаких гарантий, что функции, 
1375
определенные во всех классах-наследниках будут иметь одно и то же значение 
1376
аргумента по-умолчанию.
1377
1378
Значение аргумента по-умолчанию вычисляется каждый раз при вызове функции, что 
1379
может увеличить объем генерируемого кода. Читатель может ожидать, что такой 
1380
аргумент принимает одно и то же значение, что может сбить с толку.
1381
1382
Указатель на функции с аргументами по-умолчанию, поскольку они должны 
1383
присутствовать. Сигнатура функции может отличаться от сигнатуры вызова. 
1384
Перегрузка функций позволяет избежать этой проблемы.
1385
1386
Аргументы по-умолчанию запрещены в виртуальных функциях, где они не работают 
1387
должным образом, и в случаях, когда значение по-умолчанию может измениться в 
1388
зависимости от места, где вызов был сделан. Например, не употребляйте такие 
1389
конструкции: `void f(int n = counter++);`.
1390
1391
В ряде случаев аргументы по-умолчанию могут улучшить читаемость объявлений 
1392
функции. Если сомневаетесь, используйте перегрузку.
1393
1394
### Новый синтаксис возвращаемых значений
1395
1396
Используйте указание типа возвращаемого значение в конце функции только если 
1397
использование общепринятого синтаксиса непрактично или ухудшает читаемость.
1398
1399
C++ разрешает использовать две формы объявления функций. В общепринятой форме 
1400
возвращаемый тип появляется перед названием функции, Например:
1401
1402
``` c++
1403
int foo(int x);
1404
```
1405
1406
Новая форма использует ключевое слово `auto` перед названием функции, а тип 
1407
возвращаемого значения - после списка аргументов. Например:
1408
1409
``` c++
1410
auto foo(int x) -> int;
1411
```
1412
1413
Тип возвращаемого значения, указанного в конце функции находится уже в области 
1414
видимости функции. Для простых типов данных (например, `int`) большой разницы 
1415
нет, но она появляется в более сложных случаях, например, для типов из области 
1416
видимости класса или типов, записанных через параметры функции.
1417
1418
Тип возвращаемого значения в конце функции - это единственный способ явно 
1419
указать возвращаемый тип [лямбда-выражения](#лямбда-выражения). Компилятор не 
1420
всегда может вывести возвращаемый тип лямбда-выражения. Даже если компилятор 
1421
способен вывести тип возвращаемого значения автоматически, иногда его требуется 
1422
указать явно, например, для улучшения читаемости кода.
1423
1424
Иногда указание типа возвращаемой функции более читаемо и удобно, особенно 
1425
когда тип возвращаемого значения зависит от параметров шаблонов. Например:
1426
1427
``` c++
1428
template <typename T, typename U>
1429
auto add(T t, U u) -> decltype(t + u);
1430
```
1431
1432
Понятнее, чем
1433
1434
```c++
1435
template <typename T, typename U>
1436
decltype(declval<T&>() + declval<U&>()) add(T t, U u);
1437
```
1438
1439
Тип возвращаемого значения в конце функции - сравнительно новая особенность 
1440
языка C++, не имеющая аналого в других C-подобных языках, поэтому некоторые 
1441
читатели могут быть незнакомы с такой формой записи.
1442
1443
Существующая кодовая база содержит огромное количество старого кода. 
1444
Маловероятно, что весь этот код будет переписан под новый синтаксис, так что 
1445
реалистично предположить, что что будет использоваться либо старый синтаксис, 
1446
либо оба. Единообразие в данном случае предпочтительнее.
1447
1448
В большинстве случаев от нового синтаксиса возвращаемого значения нет особой 
1449
пользы, за исключением определения возвращаемого значения лямбда-функций или тех 
1450
случаев, когда такое написание поможет более читаемо объявить тип возвращаемого 
1451
значения. Последнее зачастую касается сложных шаблонов, использование которых 
1452
в большинстве случаев [не приветствуется](#шаблонное-метапрограммирование).
1453
1454
## Специфическая магия
1455
1456
В данной секции указаны дополнительные рекомендации по повышению надежности 
1457
кода на C++.
1458
1459
### Владение и умные указатели
1460
1461
Предпочтительно, чтобы у динамических объектов был один, конкретный владелец. 
1462
Передача объектов через умные указатели предпочтительна.
1463
1464
*Владение (ownership)* - это технология для управления выделенной памятью и 
1465
другими ресурсами. Владелец динамического объекта - это объект или функция, 
1466
которая отвечает за гарантию освобождения объекта, когда в нем больше нет 
1467
необходимости. Владение может быть *совместным (shared ownership)*, в таком 
1468
случае за его освобождение отвечает последний использующий объект. Даже в том 
1469
случае, если владение не совместное, оно может быть передано от одной сущности к 
1470
другой.
1471
1472
*Умные указатели (smart pointers)*  - это классы, которые ведут себя как 
1473
указатели, то есть, перегружают операторы `*` и `->`. Некоторые умные указатели 
1474
могут использоваться для автоматизации управления владением. Шаблон класса 
1475
`std::unique_ptr` - это умный указатель, который отвечает за единоличное 
1476
владение: Динамический объект будет уничтожен, когда `std::unique_ptr` выйдет за 
1477
пределы области видимости. Данный тип не копируемый, но переносимый для 
1478
осуществления механизма передачи владения от одного объекта к другому. Тип 
1479
`std::shared_ptr`- это умный указатель, который отвечает за совместное владение 
1480
динамическим объектом. Объекты этого типа подлежат копированию, а выделенная 
1481
память освободится с уничтожением последнего объекта `std::shared_ptr`.
1482
 * Управлять динамически выделяемыми ресурсами физически невозможно без 
1483
 какой-либо логики владения.
1484
 * Передача владения может быть дешевле, чем копирование объекта (в тех случаях, 
1485
 если оно возможно).
1486
 * Передача владения может быть проще, чем передача указателя или ссылки, 
1487
 поскольку это уменьшает необходимость в координации времени жизни объектов.
1488
 * Умные указатели делают управление владения явным и самодокументированным, что 
1489
 упрощает читаемость кода.
1490
 * Умные указатели могут целиком взять на себя управления владением, 
1491
 упрощая код, и избавляя от необходимости управления большим количеством ошибок.
1492
 * Для константных объектов, совместное владением может быть простой и эффективной заменой глубокого копирования.
1493
1494
---
1495
1496
 * Владение представляется через указатели, неважно, умные или нет. 
1497
 Семантика указателей сложнее семантики значений, особенно в API: нужно 
1498
 заботиться не только о владении, но и об именовании, времени жизни, 
1499
 изменчивости (*mutability*), помимо всего прочего.
1500
 * Затраты производительности на работу со значениями часто переоценивается, а 
1501
 выигрыш в производительности от передачи владения может не оправдать усложнения
1502
 читаемости и увеличения сложности.
1503
 * API, которое передает владение, по сути, решает за клиентов, какую модель 
1504
 управления памятью использовать.
1505
 * Умные указатели менее явно выражают, где и когда именно будут освобождены 
1506
 ресурсы.
1507
 * Передача управления через механизмы перемещения, которые использует 
1508
 `std::unique_ptr` являются сравнительно новыми и могут запутать некоторых 
1509
 программистов.
1510
 * Совместное владение - это соблазнительная альтернатива тщательному 
1511
 проектированию владения объектов, которая скрывает дизайн системы.
1512
 * Совместное владение осуществляет управление владения во время исполнения, 
1513
 что довольно затратно по ресурсам.
1514
 * В некоторых случаях (например, при циклических ссылках), объекты с 
1515
 совместным владением могут никогда не быть уничтожены.
1516
 * Умные указатели - не идеально полноценная замена для обычных.
1517
1518
Если динамическое выделение памяти необходимо, предпочитайте держать владение в 
1519
той сущности, которая ее выделила. Если другой сущности необходимо иметь 
1520
доступ к объекту, рассмотрите возможность передачи копии или передачи ссылки
1521
или указателя без передачи владения. Для того, чтобы сделать передачу владения 
1522
более явной, предпочтительнее использовать `std::unique_ptr`. Например:
1523
1524
``` c++
1525
std::unique_ptr<Foo> FooFactory();
1526
void FooConsumer(std::unique_ptr<Foo> ptr);
1527
```
1528
1529
Не используйте совместное владение без очень хорошей причины. 
1530
Например, избежать дорогостоящих операций копирования, но стоит убедиться, что 
1531
прирост производительности стоит того, а объект *неизменяемый (immutable)*, 
1532
(например, `std::shared_ptr<const Foo>`). Если нужно *именно* разделяемое 
1533
владение, используйте `std::shared_ptr`.
1534
1535
Никогда не используйте `std::auto_ptr`.
1536
1537
> _Внимание:_ Qt использует свои умные указатели, например, `QSharedPtr`, 
1538
> которые удобно использовать с данной библиотекой. Однако, конвертация из 
1539
> одного умного указателя в другой невозможна. Старайтесь использовать
1540
> `std::shared_ptr`, где это возможно, для обеспечения единообразия. Если же 
1541
> проект тесно связан с Qt, можно использовать классы из Qt. 
1542
> Единообразие здесь - самое важное.
1543
1544
### Физический уровень
1545
1546
### Утилиты автоматизации
1547
1548
### Дополнительные стандарты
1549
1550
## Другие особенности С++
1551
1552
### Ссылки на rvalue
1553
1554
Используйте *rvalue-ссылки (rvalue references)* только в некоторых особых 
1555
случаях, описанных ниже.
1556
1557
Rvalue-ссылки - это ссылки, которые могут привязываться только ко временным 
1558
объектам. Их синтаксис похож на синтаксис обычных ссылок. Например, 
1559
`void f(std::string&& s);` - это объявление функции, аргумент которой является 
1560
rvalue-ссылкой на `std::string`.
1561
1562
Когда суффикс `&&` без дополнительных квалификаторов используется с шаблонным 
1563
аргументом функции, то применяются специальные правила вывода типа аргумента. 
1564
Такая ссылка имеет название *forwarding reference*[^1].
1565
1566
 * Определение конструктора копирования делает возможность перемещать значение 
1567
 вместо копирования. Например, если `v1` имеет тип `std::vector<std::string>`, 
1568
 например, конструкция `auto v2(std::move(v1))`, вероятно приведет к простой 
1569
 манипуляции с памятью вместо копирования большого количества данных.
1570
  * Ссылки на rvalue позволяют определять перемещаемые, но не копируемые типы 
1571
данных.
1572
 * `std::move` необходим для эффективного использования некоторых библиотечных 
1573
 типов, например, `std::unique_ptr`.
1574
 * Механизм *forwarding reference*, который использует ссылку rvalue-ссылку, 
1575
 делает возможным разработку шаблонной функции, которая перенаправляет аргументы 
1576
 другой функции и работает с ними, независимо от того, какая именно ссылка 
1577
 пришла в качестве аргумента. Это называется *perfect forwarding*.
1578
1579
---
1580
1581
 * Ссылки на rvalue все еще не до конца понятны большинству программистов. Такие 
1582
 правила, как *сжатие ссылок (reference collapsing)* и специальные правила 
1583
 вывода типов данных для *forwarding reference* остаются неясными.
1584
 * Ссылки на rvalue часто используются неправильно. Использование rvalue-ссылок 
1585
 в сигнатурах, когда аргумент должен оставаться валидным или когда не было 
1586
 выполнения операции `std::move`, является неинтуитивным.
1587
1588
Не используйте rvalue-ссылки и не используйте квалификатор `&&` в методах, 
1589
за исключением следующих случаях:
1590
 * Определение конструкторов перемещения 
1591
 (см. [соответствующую секцию](#копируемые-и-перемещаемые-типы-данных)).
1592
 * Используйте `&&`-методы, которые логически "поглощают" `*this` и оставляют 
1593
 его в неиспользуемом или пустом состоянии. Обратите внимание, что это относится 
1594
 только к квалификаторам методов (после закрывающей скобки в сигнатуре функций). 
1595
 Если необходимо поглотить параметр функции, попробуйте передавать его по 
1596
 значению. 
1597
 * Для обеспечения *perfect forwarding* совместно с `std::forward`.
1598
 * Для определения пар перегрузок, например `foo(const Bar&)` и `foo(Bar&&)`.
1599
 Чаще всего, проще передать параметр по значению, но перегруженная пара функций 
1600
 часто является более производительной или необходима ,когда код должен 
1601
 работать с большим количеством типов данных. Как всегда: если для оптимизации 
1602
 нужно написать более сложный код, то нужно убедиться, что это 
1603
 действительно помогает.
1604
1605
[^1]: Не нашел нормального перевода
1606
1607
### Дружественные функции и классы
1608
1609
Дружественные (`friend`) функции и классы разрешены, если на это есть веская 
1610
причина.
1611
1612
Друзья должны быть объявлены в том же файле, чтобы для читателя не было 
1613
необходимости читать другой файл, чтобы найти, как именно используются закрытые 
1614
методы класса. Обычное использование дружественных классов - это, например, в 
1615
классе `FooBuilder`, который будет другом `Foo` и задача которого корректно 
1616
сконструировать внутреннее состояние класса `Foo`. Также это может быть полезно 
1617
при модульном тестировании.
1618
1619
Друзья классов расширяют, но не нарушают границы инкапсуляции класса. В 
1620
некоторых случаях это лучше, чем делать член публичным только если одна функция 
1621
или класс должны иметь к нему доступ. Как бы то ни было, большинство классов 
1622
должны взаимодействовать друг с другом через публичных членов.
1623
1624
### Исключения
1625
1626
*Несмотря на то, что этот стиль кодирования основан на стиле кодирование*
1627
*Google, мы используем исключения.*
1628
1629
 * Исключения позволяют обрабатывать ситуации типа «это невозможно» в функциях с 
1630
 очень большим уровнем вложенности без неясной и подверженной ошибкам работы по 
1631
 распределению кодов ошибок.
1632
 * Исключения используются в большинстве современных языков программирования и 
1633
 их  использование в C++ позволяет писать код, концептуально схожий с Python, 
1634
 Java и др.
1635
 * Некоторые библиотеки C++ используют исключения в своей работе и отказ от них 
1636
 может существенно усложнить интеграцию с ними.
1637
 * Исключения являются единственным способом сообщения об ошибках в 
1638
 конструкторе. Можно обойти это используй фабричные методы, метод `Init()` или 
1639
 специальное, невалидное состояние, но это потребует либо выделения памяти, либо 
1640
 особого состояния.
1641
 * Исключения полезны в каркасах тестирования.
1642
 * Исключения позволяют сепарировать код, который генерирует ошибку от кода, 
1643
 который их обрабатывает.
1644
 * Механизм исключений хорошо ложится на формализацию требований к программе в 
1645
 виде *вариантов использования (use cases)*.
1646
1647
---
1648
1649
 * Когда вы добавляете выражение `throw` к существующей функции, нужно проверить 
1650
 всех, кто эту функцию вызывает. Необходимо либо обеспечить базовый уровень 
1651
 безопасных исключений (*exception safety levels*), либо нормально относиться к 
1652
 аварийному завершению работы программы. Если `f()` вызывает `g()`, который 
1653
 вызывает `h()`, а в `h` выбрасывается исключение, которое ловится в `f`, то `g` 
1654
 может не очищаться так, как нужно.
1655
 * Исключения делают сложным понимание потока управления, поскольку у функции 
1656
 есть, по-сути, несколько мест завершения. 
1657
 * Безопасность исключений требует применения дополнительных практик, например, 
1658
 RAII. 
1659
 * Использование исключений ведёт к распуханию бинарного файла программы, 
1660
 увеличивает время компиляции, и вообще может привести к проблемам с адресным 
1661
 пространством.
1662
 * Доступность исключений может провоцировать разработчиков выбрасывать их по 
1663
 поводу и без. Например, ввод неверного текста, очевидно, не должен приводить к 
1664
 возникновению исключения и т.п.
1665
1666
Для того, чтобы обработка исключений была максимально безболезненной, 
1667
используйте парадигму RAII и новые механизмы исключений, такие как 
1668
`std::exception_ptr`, `std::nested_exception`, `std::current_exception`, 
1669
`std::rethrow_exception`, `std::nested_exception` и т. д.
1670
1671
Наследуйте классы исключений от `std::exception`, а еще лучше - от кого-то из 
1672
классов-наследников, по типу `std::runtime_error` и т.п.
1673
1674
Желательно сперва проверить все предусловия функции и выполнить все возможные 
1675
исключения, а затем исполнять основное тело функции. Это не всегда возможно и 
1676
иногда ухудшает читаемость, но чаще всего - улучшает.
1677
1678
Убедитесь, что инварианты состояний классов не нарушаются при возникновении 
1679
исключения, которое планируется обрабатывать.
1680
1681
Важно понимать, что исключительная ситуация - это такая ситуация, которую 
1682
сущность не в состоянии парировать сама, и парирование которой выходит за рамки 
1683
функциональных требований к программе. То есть, если решение о том, как 
1684
действовать в случае возникновения той или иной ситуации выходит за рамки уровня 
1685
абстракции текущего класса, то, вероятно, можно кидать исключения.
1686
1687
### Ключевое слово `noexcept`
1688
1689
Используйте ключевое слово `noexcept`, если это полезно и корректно.
1690
1691
Спецификатор `noexcept` используется для того, чтобы указать, будет или нет 
1692
функция генерировать исключения или нет. Если исключение выйдет за область 
1693
видимости, программа вылетит через `std::terminate`.
1694
1695
Использование оператора `noexcept` приводит к проверкам времени компиляции, 
1696
которые проходят, если выражение было разработано так, чтобы не генерировать 
1697
никаких исключений.
1698
1699
 * Спецификация конструктора перемещения как `noexcept` может повысить 
1700
 производительность в некоторых случаях. Например, `std::vector<T>::resize` 
1701
 использует семантику перемещения в том случае, если конструктор перемещения для 
1702
 типа `T` специфицирован как `noexcept`.
1703
 * Если функция отмечена как `noexcept`, компилятор может применить 
1704
 дополнительную оптимизацию там, где включены исключения, поскольку не вставляет 
1705
 кода для раскрутки стека (*stack unwinding*) там, где не будут генерироваться 
1706
 исключения.
1707
1708
---
1709
1710
 * Тяжело в будущем убрать `noexcept` из функции, поскольку ее клиенты будут 
1711
ожидать, что функция `noexcept` и появление исключения в неожиданном месте 
1712
может быть сложным для обнаружения.
1713
1714
Использование `noexcept` допустимо в тех случаях, когда это полезно для 
1715
повышения производительности, если это полностью согласуется с семантикой 
1716
функции, то есть, должно быть нормально, что если в данной функции возникнет 
1717
исключение - то это фатальная ошибка. Самый первый кандидат - конструктор 
1718
перемещения. Если имеет смысл добавить спецификатор `noexcept` к какой-то 
1719
другой функции, проконсультируйтесь с начальством.
1720
1721
Используйте безусловный `noexcept`, когда исключения невозможны. В противном 
1722
случае используйте условные спецификаторы `noexcept` с простыми условиями, 
1723
которые на выполняются только в очень редких случаях, когда функция может 
1724
сгенерировать исключение. Можно, например, использовать проверки 
1725
*особенностей типов (type traits)* или особые условия, когда какая-либо операция
1726
может сгенерировать исключение (`std::is_nothrow_move_constructable`), или 
1727
когда выделение памяти может сгенерировать исключение 
1728
(*absl::default_allocator_is_nothrow*). Скорее всего, если возникла ошибка 
1729
аллокации или закончилась память, то это, скорее причина возникновения фатальной 
1730
ошибки, чем исключения, от которого программа сможет оправиться. В любом случае, 
1731
простота интерфейса приветствуется и, наверное, лучше написать `noexcept` без 
1732
условий, чем описывать *очень сложные* условия внутри спецификатора `noexcept`, 
1733
если есть причина сделать функцию `noexcept`.
1734
1735
### RTTI
1736
1737
Избегайте использования RTTI. 
1738
1739
*RTTI (runtime-type information)* - это механизм, позволяющий программисту 
1740
запрашивать класс объекта во время исполнения. Это делается путем использования 
1741
`typeid` или `dynamic_cast`. 
1742
1743
Стандартные альтернативы RTTI (как описано ниже) требуют модификации или 
1744
переделки дизайна иерархии классов. Иногда такие модификации сложны и 
1745
нежелательны, особенно коде на поздних стадиях.
1746
1747
RTTI удобно использовать в некоторых модульных тестах. Например, тесты фабричных 
1748
классов, в которых тест должен верифицировать, что у создаваемые объекты имеют 
1749
нужный тип. Также это удобно при управлении отношением между объектами и их 
1750
заглушками.
1751
1752
RTTI удобно использовать при работе с несколькими абстрактными объектами. 
1753
Например:
1754
1755
```c++
1756
bool Base::Equal(Base* other) = 0;
1757
bool Derived::Equal(Base* other) {
1758
    Derived* that = dynamic_cast<Derived*>(other);
1759
    if(that == nullptr)
1760
        return false;
1761
...
1762
}
1763
```
1764
1765
Сам по себе запрос типа объекта во время исполнения - это сигнал о потенциальных 
1766
проблемах в проектировании. Часто необходимость в использовании RTTI говорит о 
1767
том, что в иерархии объектов есть изъяны.
1768
1769
Бесконтрольное использование RTTI ведет к тому, что код становится трудно 
1770
поддерживать. Это ведет к деревьям решений, основанным на типах данных, которые 
1771
будут рассыпаны по всему коду, которые придется изучать при внесении изменений 
1772
в код.
1773
1774
Использование RTTI допустимо, но может легко привести к злоупотреблению, поэтому 
1775
применять следует с осторожностью. Использование в модульных тестах допускается 
1776
без ограничений, но в коде его следует максимально избегать. В частности, 
1777
подумайте дважды перед использованием RTTI в новом коде. Если вам необходимо 
1778
написать код, который ведет себя в зависимости от класса объекта, попробуйте 
1779
рассмотреть следующие альтернативы:
1780
 * Виртуальные методы - это предпочтительный способ исполнения различных частей 
1781
кода в зависимости от специфического типа подкласса. Тогда вся работа будет 
1782
сделана внутри объекта.
1783
 * Если код находится вне объекта, то можно использовать механизмы 
1784
множественной диспетчеризации. Например, шаблон проектирования Visitor.
1785
1786
Если логика программы гарантирует, что объект базового класса - это фактически 
1787
объект определенного класса-наследника, то можно свободно использовать 
1788
`dynamic_cast`. Часто в подобных ситуациях можно использовать `static_cast`.
1789
1790
Деревья решений, основанные на типах - это верный признак того, что разработка 
1791
движется не в том направлении
1792
1793
```c++
1794
if(typeid(*data) == typeid(D1)) {
1795
...
1796
} 
1797
else if(typeid(*data) == typeid(D2)) {
1798
...
1799
}
1800
else if(typeid(*data) == typeid(D3)) {
1801
...
1802
```
1803
1804
Подобный код обычно ломается при добавлении нового класса. Более того, когда 
1805
свойства уже имеющихся классов меняются, сложно найти и модифицировать все 
1806
связанные сегменты кода.
1807
1808
> Не стоит изобретать собственный аналог RTTI. Как правило, минусы RTTI будут
1809
> касаться и этих аналогов.
1810
1811
### Приведение типов
1812
1813
Используйте приведение типов в стиле C++, например, 
1814
`static_cast<float>(double_value)` или инициализацию с помощью фигурных скобок 
1815
для арифметических типов, например `int64_t y = int64_t{1} << 42`. Не 
1816
используйте приведение типов формата C, например `(int) x`, кроме случаев 
1817
приведения к типу `void`. Используйте формат `T(x)` только если `T` - класс.
1818
1819
В C++ присутствует отличная от C система приведения типов, которая разделяет
1820
 различные операции приведения.
1821
1822
Главная проблема с приведением в C - неоднозначность, иногда происходит 
1823
конверсия типов `(int)3.5`, иногда приведение, например `(int)"hello"`. 
1824
Инициализация в фигурных скобках и приведение типов из C++ помогают избежать 
1825
этой неоднозначности. Также это приведение легко найти в коде поиском или 
1826
благодаря подсветке синтаксиса.
1827
1828
Приведение типов на C++ многословно и громоздко.
1829
1830
В общем, не используйте приведение в стиле C. Вместо этого используйте 
1831
приведением в стиле C++, если требуется явное преобразование типов.
1832
1833
 * Используйте инициализацию в фигурных скобках для арифметических типов. Это 
1834
самый безопасный способ, поскольку код не компилируется в том случае, если 
1835
возможна потеря информации. Синтаксис в таком случае выйдет довольно лаконичным.
1836
 * Используйте `absl::implicit_cast` для безопасного приведения типов вверх по 
1837
иерархии классов. Например для приведения `Foo*` к `SuperclassOfFoo` или `const 
1838
Foo*`. Как правило, это делается автоматически компилятором, но иногда нужно 
1839
делать явно, например, для оператора `?:`.
1840
 * Используйте `static_cast` как эквивалент приведения типов из C, которое 
1841
конвертирует значение или при необходимости явно преобразовать класс к 
1842
классу-наследнику. В этом случае вы должны быть уверены, что объект на самом 
1843
деле является объектом класса-наследника.
1844
 * Используйте `const_cast` для того, чтобы убрать модификатор 
1845
[const](#ключевое-слово-const).
1846
 * Используйте `reinterpret_cast` для небезопасного приведения указателей, 
1847
включая `void*`. Используйте это только когда знаете, что делаете. Рассмотрите 
1848
`absl::bit_cast` в качестве альтернативы.
1849
 * Используйте `absl::bit_cast` для приведения "сырых" битов в другой тип того 
1850
же размера, например, `double` в `int64_t`.
1851
1852
В [секции бо RTTI](#RTTI) описано использование `dynamic_cast`.
1853
1854
### Потоки ввода-вывода
1855
1856
Используйте потоковый ввод-вывод когда необходимо. Перегружайте операцию `<<` 
1857
только для типов, которые представляют собой данные и специализируйте только 
1858
значения, доступные для пользователя, без деталей реализации. 
1859
1860
Потоки - это стандартный способ ввода/вывода в C++. Они широко используются для 
1861
логирования и тестовой диагностики.
1862
1863
Потоки предоставляют простой в освоении API для форматированного ввода-вывода, 
1864
который легко портировать и повторно использовать. Для сравнения, например, 
1865
`printf` не поддерживает `std::string`, не говоря уже о пользовательских типах 
1866
данных. Также сложно разрабатывать портируемый код, использующий `printf`. 
1867
Кроме того, printf вынуждает выбирать среди похожих версий одной функции и 
1868
ориентироваться в десятках форматных символах.
1869
1870
Потоки обеспечивают хорошую поддержку консольного ввода-вывода через `std::cin`, 
1871
`std::cout`, `std::cerr`, `std::clog`. Функции из C API тоже неплохо работают, 
1872
но могут требовать ручной буферизации ввода.
1873
1874
---
1875
1876
 * Форматирование потоков может изменять состояние потока. Это состояние будет 
1877
постоянным и влиять на весь последующий ввод-вывод до тех пор, пока вы не 
1878
будете возвращаться к предыдущему состоянию каждый раз. Более того, 
1879
пользовательский код может не только модифицировать уже имеющееся состояние, 
1880
но и вводить новые.
1881
 * Поскольку код и данные перемешаны во время вывода потока, то сложно 
1882
контролировать, что и как именно будет выведено в поток.
1883
 * Формирование вывода посредством вызова цепочки операторов `<<` затрудняет 
1884
локализацию, т.к. при этом жёстко фиксируется порядок слов. 
1885
 * API потоков сложен в освоении, поэтому программисты должны обладать большим 
1886
опытом для его грамотного использования.
1887
 * Выборка нужной перегрузки оператора `<<` - затратная для компилятора 
1888
операция.
1889
1890
Используйте потоковый ввод-вывод только если это лучшее решение проблемы. 
1891
Библиотеки для логирования часто лучший выход, чем `std::cerr` или `std::clog`, 
1892
а библиотеки для работы со строками лучше, чем `std::stringstream`. Если код 
1893
использует Qt, то лучше всего использовать отладочные потоки по типу `qDebug` и 
1894
`QString`, соответственно. Если нет - найдите подходящую легковесную библиотеку. 
1895
1896
Не используйте потоки для ввода-вывода данных для конечного пользователя или 
1897
там, где нет доверия к данным. Найдите подходящую библиотеку, которая 
1898
поддерживает локализацию, поддержку защиты информации и т. п.
1899
1900
При использовании потоков избегайте API, которые меняют состояние потоков, 
1901
например `imbue()`, `xalloc()` или `register_callback()`. Используйте явные 
1902
функции форматирования, например, `absl::StreamFormat()` вместо потоковых 
1903
манипуляторов.
1904
1905
Перегружайте оператор `<<` только для типов, если тип представляет собой 
1906
значение и необходимо выводит человекочитаемые данные. Избегайте вывода в 
1907
поток деталей реализации. Если нужно выдать отладочную информацию, используйте 
1908
обычные функции или методы. Например, добавьте в класс метод `debugString()`, 
1909
который вернет такую информацию в виде `std::string`.
1910
1911
### Преинкремент и предекремент
1912
1913
Используйте префиксные формы (`++i`) за исключением тех случаев, когда вам явно 
1914
необходима постфиксная семантика.
1915
1916
Когда переменная инкрементируется (`++i`/`i++`) или декрементируется 
1917
(`--i`/`i--`) и значение выражения не используется, необходимо четко решать,
1918
какой вид инкремента/декремента используется.
1919
1920
Префиксные операции эффективнее в тех случаях, когда значение выражения 
1921
игнорируется, поскольку они не требуют создания копии переменной. Помимо этого, 
1922
постфиксная операция труднее читается.
1923
1924
Раньше везде использовали постфиксный формат в циклах, поэтому он привычнее.
1925
1926
Используйте префиксный формат (`++i`/`--i`) во всех случаях, когда коду не 
1927
нужна именно постфиксная семантика.
1928
1929
### Ключевое слово `const`
1930
1931
Используйте `const` везде, где это имеет смысл. В некоторых случаях 
1932
`constexpr` - лучший вариант.
1933
1934
При объявлении переменных или параметров можно указать ключевое слово `const` 
1935
для обозначения того, что значение переменной не будет меняться 
1936
(`const int foo`). Функции-члены классов могут иметь квалификатор `const`, 
1937
чтобы обозначить, что функция не меняет состояния переменных класса 
1938
(`class Foo { int Bar(char c) const; };`). 
1939
1940
В таком случае читателю будет понятнее, как именно переменная или функция будет 
1941
использоваться. Также это позволяет компилятору проводить оптимизацию и 
1942
генерировать более производительный код. Также `const` повышает надежность 
1943
программы, поскольку явно декларирует, будут ли данные меняться или нет. 
1944
Позволяет пользователям понимать, что функции безопасны для использования без 
1945
блокировок в многопоточных программах.
1946
1947
Использование `const` - очень заразное. Если в функцию передается 
1948
`const`-переменная, то в прототипе также должен стоять `const` или потребуется 
1949
`const_cast`. Это может затруднить использование библиотечных функций.
1950
1951
Ключевое слово `const` настоятельно рекомендуется к использованию в API 
1952
(например, в параметрах функций, методах, нелокальных переменных) везде, где это 
1953
осмысленно и точно. Это делает предоставляет целостное и верифицированное 
1954
компилятором описание, какие объекты будут изменяться при вызове. Четкое и 
1955
надежное разделение чтения и записи критично для разработки потокобезопасного 
1956
кода и полезно во многих других случаях. В частности:
1957
 * Если функция не меняет значение аргумента, передаваемого по значению или по 
1958
 указателю, соответствующий параметр должен быть ссылкой или указателем на 
1959
 константу (`const T&`/`const T*`). 
1960
 * Если параметр передается по значению, использование `const` не имеет эффекта 
1961
 и не рекомендуется.
1962
 * Объявляйте методы как `const`, если они не меняют значения объекта (и не дают 
1963
 такой возможности, например, возвращая неконстантную ссылку) и могут безопасно 
1964
 вызываться из нескольких потоков.
1965
1966
Использование `const` для локальных переменных остается на усмотрение 
1967
программиста.
1968
1969
Все `const`-методы класса должны иметь возможность вызываться одновременно из 
1970
разных потоков. В противном случае класс должен быть явно задокументирован как 
1971
небезопасный.
1972
1973
#### Где использовать `const`
1974
1975
Некоторым людям нравится `int const* foo` вместо `const int* foo`. Так делать не 
1976
надо, `const int* foo` звучит как словосочетание на английском языке. 
1977
1978
### Ключевое слово `constexpr`
1979
1980
Используйте `constexpr`, чтобы определять истинные константы времени компиляции
1981
или чтобы гарантировать константную инициализацию.
1982
1983
Некоторые переменные могут быть объявлены как `constexpr`, чтобы обозначит 
1984
истинные константы, т.е., константы времени компиляции или компоновки. Некоторые 
1985
функции или конструкторы могут быть объявлены как `constexpr`, чтобы обозначить, 
1986
что они могут быть использованы в `constexpr`-выражениях.
1987
1988
Использование `constexpr` позволяет, например, создать константу в виде 
1989
выражения с плавающей запятой, которое будет вычисляться во время компиляции 
1990
вместо использования литералов, а также использовать в этих выражениях вызовы 
1991
функций.
1992
1993
Если помечать что-то как `constexpr` слишком рано, то могут возникнуть 
1994
проблемы с миграцией, если позже будет необходимо убрать `constexpr`. 
1995
Ограничения, что можно и что нельзя использовать в `constexpr`-функциях или 
1996
конструкторах могут привести к использованию неочевидных обходных путей.
1997
1998
Самый надежный способ объявить константу в интерфейсе - это `constexpr`. 
1999
Используйте `constexpr`, чтобы определять истинные константы и функции, которые 
2000
можно для них использовать. Не усложняйте функцию для использования с 
2001
`constexpr`. Не используйте `constexpr`, чтобы заставить компилятор делать 
2002
функции встроенными (inline).
2003
2004
### Целочисленные типы данных
2005
2006
Из встроенных целочисленных типов данных C++ следует использовать только `int`. 
2007
Для переменных других типов используйте целочисленные типы данных с точными 
2008
размерами из `<cstdint>`, например, `int16_t`. Для работы с системой 
2009
метаобъектов из библиотеки Qt допустимо использование типов данных из 
2010
заголовочного файла `<QtGlobal>`. Держите в уме, что даже если для результата 
2011
требуется меньший размер типа данных, промежуточный результат вычислений может 
2012
требовать типа данных побольше. Если сомневаетесь, используйте тип данных 
2013
побольше.
2014
2015
C++ не уточняет размер целочисленных типов, таких как `int`. Обычно люди 
2016
предполагают, что `short` содержит 16 битов, `int` — 32, `long` — 32 и `long 
2017
long` содержит 64 бита.
2018
2019
Размер целочисленных типов зависит от аппаратной архитектуры.
2020
2021
В стандартном заголовочном файле `<cstdint>` определены типы, такие как: 
2022
`int16_t`, `uint32_t`, `int64_t` и т.д. Не используйте `short`, `unsigned long`, 
2023
`long`, чтобы быть уверенными в размере типа данных. Из целочисленных типов 
2024
языка C можно использовать только `int`. Также, в соответствующих случаях, 
2025
используйте `size_t` и `ptrdiff_t`. Тип `int` используется очень часто, особенно 
2026
для небольших значений, например как счётчики в циклах. Можете считать, что 
2027
`int` содержит минимум 32 бита (но не больше). Если требуется 64 битный 
2028
целочисленный тип, то следует использовать `int64_t` или `uint64_t`.
2029
2030
Для целых чисел, которые могут быть *большими*, используйте `int64_t`.
2031
2032
Не стоит использовать беззнаковые числа (например, `uint32_t`). Допустимое 
2033
применение беззнаковых чисел это использование битовых представлений или 
2034
использование переполнения (по модулю `2^N`) в расчётах. В частности, не 
2035
используйте беззнаковый тип для того, чтобы убедиться, что число всегда будет 
2036
положительным. Используйте `assert`, чтобы это гарантировать. 
2037
2038
Если вы разрабатываете контейнер, который возвращает размер, убедитесь, что типа 
2039
данных хватит для любого потенциально возможного использования контейнера. Если 
2040
сомневаетесь - используйте тип данных большего размера.
2041
2042
Будьте внимательны при конвертировании целочисленных типов. Может проявится 
2043
*неопределённое поведение (undefined behavior)*, ведущее к ошибкам 
2044
безопасности и другим проблемам.
2045
2046
#### Беззнаковые целочисленные типы
2047
2048
Беззнаковые целые числа хороши для представления битовых полей и модульной 
2049
арифметики. Исторически сложилось, что в стандарте C++ для размеров контейнеров 
2050
используется беззнаковый тип. Многие из разработчиков стандарта признают, 
2051
что это была ошибка, но в данный момент это невозможно эффективно исправить.
2052
Беззнаковая арифметика отличается от простой целочисленной, а соответствует 
2053
стандартам *модульной арифметики*, то есть переходят через 0 при переполнении. 
2054
Это приводит к ошибкам, которые невозможно выявить компилятором. Также, это 
2055
затрудняет оптимизацию.
2056
2057
Смешивание знаковых и беззнаковых целочисленных типов приводит к такому же 
2058
количеству проблем. Лучший совет: старайтесь использовать итераторы вместо 
2059
указателей и размеров, старайтесь не смешивать знаковые и беззнаковые типы 
2060
данных и старайтесь избегать беззнаковых типов за исключением битовых полей и 
2061
тех случаев, где явно нужна модульная арифметика. Не используйте беззнаковый тип 
2062
только для того, чтобы гарантировать, что переменная неотрицательна.
2063
2064
### Переносимость на 64-битные системы
2065
2066
Код должен одинаково хорошо работать как с 64-битной, так и с 32-битной 
2067
архитектурой. Держите в уме проблемы печати, сравнений и выравнивания структур.
2068
2069
 * Переносимое использование `printf` предполагает использование неприятных и 
2070
непрактичных макросов (`PRI`-макросы из `<cinttypes>`). Не используйте `API`,
2071
которые зависят от семейства `printf`. Вместо этого используйте безопасное 
2072
целочисленное форматирование, например `StrCat` или `Substitute` из библиотеки 
2073
`absl` или `std::ostream`.
2074
    > К сожалению, `PRI`-макросы - это единственный переносимый способ, чтобы  
2075
    > указать в `printf` форматирование для целочисленных типов данных с 
2076
    > точными размерами (например, `int64_t, uint64_t, int32_t, uint32_t` 
2077
    > и т.д.). Избегайте использование `printf`. Если невозможно, используйте 
2078
    > типы данных, для которых у `printf` есть выделенный формат, например 
2079
    > `size_t(z)`, `ptrdiff_t(t)`, `maxint_t(j)`.
2080
 * Помните, что `sizeof(void*) != sizeof(int)`. Используйте `intptr_t`, если вым необходим знаковый тип такой же размерности, что и указатель. 
2081
 * Будьте осторожны с выравнивание структур, в частности при сериализации на 
2082
 диск. Класс/структура, в которых есть член типа `int64_t` или `uint64_t` 
2083
 по-умолчанию имеют выравнивание по границе 8 байт в 64-битных системах. При 
2084
 работе со структурами, которые сохраняются на диске и используются 32-битным и 
2085
 64-битным кодом, необходимо убедиться, что данные выровнены одинаково. В gcc 
2086
 можно использовать `__attribute__((packed))`. В MSVC имеется `#pragma pack()` 
2087
 и `__declspec(align())`.
2088
 * Используйте инициализацию в фигурных скобках, если требуется создать 
2089
 64-битную константу. Например:
2090
2091
    ```c++
2092
    int64_t my_value{0x123456789};
2093
    uint64_t my_mask{3ULL << 48};
2094
    ```
2095
2096
### Макросы препроцессора
2097
2098
Избегайте определения макросов, особенно в заголовочных файлах. Вместо этого 
2099
используйте встраиваемые функции, перечисления или переменные-константы. Если 
2100
используете макросы, то в имени используйте префикс—название проекта. Не 
2101
используйте макросы, чтобы переопределить или дополнить C++ API.
2102
2103
Макросы подразумевают, что код, который в видите - не тот код, который выдается 
2104
на вход компилятору. Это может вызвать неожиданное поведение, особенно если 
2105
макросы имеют глобальную область видимости. 
2106
2107
Проблемы, связанные с макросами особенно усугубляются, когда они используются 
2108
для определения фрагментов API C++. При любых ошибках в использовании API 
2109
потребуется разбираться в логике макросов; увеличивается время разбора код 
2110
инструментами рефакторинга или анализаторами. Как результат, использование 
2111
макросов в таких случаях запрещено. Например, откажитесь от подобного кода:
2112
2113
```c++
2114
class WOMBAT_TYPE(Foo) {
2115
   // ...
2116
public:
2117
    EXPAND_PUBLIC_WOMBAT_API(Foo)
2118
    EXPAND_WOMBAT_COMPARISONS(Foo, ==, <)
2119
};
2120
```
2121
2122
К счастью, макросы не так необходимы в C++, как в языке C. Вместо макросов для 
2123
высокопроизводительного кода можно использовать встраиваемые функции. Вместо 
2124
макросов, которые хранят константы, используйте `const`. Вместо использования 
2125
макросов для укорачивания длинных названий переменной используйте ссылки. 
2126
Старайтесь не использовать условную компиляцию, это усложняет тестирование.
2127
2128
Макросы позволяют делать вещи, которые невозможно сделать без них и вы будете 
2129
их видеть и использовать, особенно в низкоуровневом коде. Некоторые специальные 
2130
приемы, (такие как преобразование в строку, конкатенация и т.п.) невозможно 
2131
провернуть без их использования. Но прежде, чем использовать макрос, попробуйте 
2132
найти способ достичь того же результата по-другому. Если же вам нужен макрос для 
2133
определения интерфейса, проконсультируйтесь с руководством.
2134
2135
Следующие правила помогут избежать многих проблем, связанных с макросами. 
2136
Следуйте им когда это возможно:
2137
 * Не определяйте макрос в заголовочном файле.
2138
 * Определяйте макросы (`#define`) как можно ближе к месту первого 
2139
 использования. Удаляйте (`#undef`) сразу после последнего.
2140
 * Не делайте `#undef` существующих макросов для того, чтобы определить новый с 
2141
 таким же названием. Вместо этого придумайте уникальное название для своего 
2142
 макроса.
2143
 * Старайтесь не использовать макросы, которые при раскрытии превращаются в 
2144
 большие, несбалансированные конструкции на C++. По крайней мере, как следует 
2145
 их документируйте.
2146
 * Старайтесь не использовать препроцессорную конкатенацию (`##`) для того, 
2147
 чтобы сгенерировать название функции/класса/переменной.
2148
2149
Настоятельно не рекомендуется экспортировать макросы из заголовочных файлов 
2150
(т.е. определять макрос и не удалять его в конце заголовочного файла). Если 
2151
макрос экспортируется из заголовочного файла, то его название должно быть 
2152
глобально-уникальным. Как вариант, добавьте префикс с пространством имён 
2153
проекта (заглавными буквами). 
2154
2155
Макросы бывают необходимы при определении заголовочных файлов разделяемых 
2156
библиотек в ОС Windows. Например
2157
2158
``` c++
2159
#ifdef MY_LIBRARY
2160
#define MY_LIBRARY_PUBLIC_API __declspec(dllexport)
2161
#else
2162
#define MY_LIBRARY_PUBLIC_API __declspec(dllimport)
2163
#endif
2164
```
2165
2166
### `0`, `NULL` и `nullptr`
2167
2168
Используйте `nullptr` для нулевых указателей и `\0` для символа конца строки.
2169
2170
Использование `nullptr` для указателей улучшает безопасность типов.
2171
2172
Использование `\0` для символа конца строки делает код более читаемым.
2173
2174
### sizeof
2175
2176
Использование `sizeof(переменная)` вместо `sizeof(тип)` предпочтительнее.
2177
2178
Используйте `sizeof(переменная)` тогда, когда вам необходимо узнать размер 
2179
переменной. Если тип переменной изменится, то и значение `sizeof(переменная)` 
2180
обновится. Используйте `sizeof(тип)` в тех случаях, когда код не работает с 
2181
конкретной переменной.
2182
2183
``` c++
2184
MyStruct data;
2185
memset(&data, 0, sizeof(data));
2186
memset(&data, 0, sizeof(MyStruct)); // Плохо
2187
```
2188
2189
``` c++
2190
if(raw_size < sizeof(int)) {
2191
    LOG(ERROR) << "compressed record not big enough for count: " << raw_size;
2192
    return false;
2193
}
2194
```
2195
2196
### Вывод типов данных (в том числе `auto`)
2197
2198
Используйте *вывод типов данных (type deduction)* только в том случае, когда 
2199
это сделает код понятнее для людей, не знакомых с проектом или если это делает 
2200
код безопаснее. 
2201
Не используйте его только для того, чтобы избежать неудобства от явного описания 
2202
типа.
2203
2204
Существует несколько ситуаций, в которых C++ позволяет (или даже требует), 
2205
чтобы тип данных был выведен компилятором вместо того, чтобы быть явно указанным 
2206
в коде.
2207
2208
_Вывод типов данных в шаблонах функций_
2209
2210
 > Шаблон функции может быть вызван без явного указания параметров шаблона. Компилятор выводит их из типов аргументов функции:
2211
2212
 > ```c++
2213
 > template <typename T>
2214
 > void f(T t);
2215
 >
2216
 >f(0); // Вызывается f<int>(0)
2217
 > ```
2218
2219
_Переменные с типом `auto`_:
2220
2221
 > Объявление переменной может использовать ключевое слово `auto` вместо типа 
2222
 > данных. Компилятор определяет тип из выражения инициализации, следуя 
2223
 > правилам, аналогичным для шаблонной функции, пока не используются фигурные 
2224
 > скобки:
2225
2226
 > ```c++
2227
 > auto a = 42; // a типа int
2228
 > auto& b = a; // b типа int&
2229
 > auto c = b; // c типа int
2230
 > auto d{42}; // d типа int, а не std::initializer_list<int>
2231
 > ```
2232
 > Ключевое слово `auto` может быть использовано с квалификатором `const` или 
2233
 > как часть ссылки или указателя, но его нельзя использовать как аргумент 
2234
 > шаблона. Более редкий способ использования: 
2235
 > `decltype(auto)`, когда тип выводится из применения `decltype` к 
2236
 > выражению инициализации.
2237
2238
_Вывод типа возвращаемого значения функции_
2239
 > Ключевое слово `auto` может применяться также и вместо типа возвращаемого 
2240
 > значения функции. В таком случае компилятор определит тип возвращаемого 
2241
 > значения из тела функции, следуя правилам для определения типов переменных:
2242
2243
 > ``` c++
2244
 > auto f() { return 0; } // Возвращаемый f тип - int
2245
 > ```
2246
2247
 > Возвращаемый тип лямбда-функции также выводится подобным образом, но это 
2248
 > делается путем опускания типа возвращаемого значения, без использования 
2249
 > `auto`. Запутывает, что для 
2250
 > [указания возвращаемого типа в конце](#новый-синтаксис-возвращаемых-значений) 
2251
 > функции также необходимо использовать `auto`.
2252
2253
_Обобщенные (generic) лямбда-функции_
2254
 > Лямбда-выражение может использовать ключевое слово `auto` вместо типа одного 
2255
 > или нескольких типов параметров. В таком случае лямбда-функция становится 
2256
 > шаблоном функции со своим шаблонным параметром для каждого параметра функции, 
2257
 > для которого вместо типа указано `auto`:
2258
 
2259
 > ``` c++
2260
 > // Сортируем `vec` по возрастанию
2261
 > std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });
2262
 > ```
2263
2264
_Инициализация переменных захвата лямбда-функции_
2265
 > В секции захвата лямбда-функции новые переменные, инициализированные 
2266
 > значениями:
2267
 >
2268
 > ``` c++
2269
 > [x = 42, y = "foo"] { ... } // тип x - int, y - const char*
2270
 > ```
2271
 >
2272
 > Синтаксис не позволяет указать тип новой переменной, он выводится по тем же 
2273
 > правилам, что и `auto`-переменные. 
2274
 
2275
_Вывод типа аргумента шаблона класса_
2276
 > См. [соответствующий раздел](#вывод-аргументов-шаблонов-классов).
2277
2278
_Структурные привязки_
2279
 > При объявлении кортежей, структур, или массивов с использованием ключевого 
2280
 > слова `auto` можно указать названия отдельных элементов вместо названия 
2281
 > целого объекта. Это называется *структурная привязка (structured binding)*, а 
2282
 > сам объявление называется *объявлением структурной привязки* 
2283
 > *(structured binding declaration)*. Синтаксис не позволяет задать тип ни 
2284
 > полного объекта, ни отдельных имён:
2285
 >
2286
 > ``` c++
2287
 > auto [iter, success] = my_map.insert({key, value});
2288
 > if(!success) {
2289
 >     iter->second = value;
2290
 > }
2291
 > ```
2292
 >
2293
 > Ключевое слово `auto` может быть квалифицировано как `const`, `&`, `&&`, 
2294
 > но заметим, что эти квалификаторы применяются ко всему анонимному массиву/
2295
 > кортежу/структуре, а не к отдельным привязкам. Правила определения конечного 
2296
 > типа привязок довольно сложны, но результат обычно предсказуем. Можно только 
2297
 > отметить, что тип привязки обычно не может быть ссылочным, даже если в 
2298
 > декларации указана ссылка (хотя поведение всё равно может быть как у ссылки).
2299
2300
Приведенная выше информация опускает некоторые детали, поэтому изучите вопрос 
2301
самостоятельно.
2302
2303
 * Названия типов данных в C++ могут быть длинными и громоздкими, особенно при 
2304
 использовании шаблонов или пространств имен.
2305
 * Когда название одного и того же типа данных повторяется много раз внутри 
2306
 небольшого участка кода, это не улучшает читаемость.
2307
 * Иногда вывод типа данных безопаснее, поскольку позволяет избегать случайного 
2308
 копирования или преобразования типов.
2309
2310
Как правило код на C++ яснее, когда все типы данных указываются явно, особенно 
2311
если вывод типов опирается на информацию, указанную в отдаленной части кода. В 
2312
выражениях вроде:
2313
2314
``` c++
2315
auto foo = x.add_foo();
2316
auto i = y.Find(key);
2317
```
2318
2319
может быть непонятно, какой тип данных будет выведен, особенно тип переменной 
2320
`y` не очень популярен или если она была объявлена много строк назад.
2321
2322
Программистам необходимо понимать, когда вывод типов данных будет или нет 
2323
ссылкой или в неожиданном месте может случиться копирование.
2324
2325
Если выводимые типы используются как часть интерфейса, программисты могут 
2326
изменить этот тип при попытке изменить значение, что приведет к радикальным 
2327
изменениям в API.
2328
2329
_Фундаментальное правило таково_: Используйте вывод типов данных только для 
2330
того, чтобы сделать код чище и понятнее. Не используйте его только для того, 
2331
чтобы избежать неудобства от явного описания типа. Рассуждая о том, будет ли код 
2332
чище и понятнее, стоит держать в уме, что читатели кода могут относиться к 
2333
другому подразделению или не быть знакомыми с вашим проектом. Если явное 
2334
указание типов данных может показаться избыточным для членов вашей команды, оно, 
2335
тем не менее, может содержать полезную информацию для других. Например, 
2336
возвращаемый тип `std::make_unique<foo>()` можно считать очевидным, то для 
2337
функции `MyWidgetFactory()`, вероятно, нет.
2338
2339
Эти принципы применимы ко всем случаям вывода типов данных, но детали могут 
2340
отличаться для разных случаев.
2341
2342
#### Вывод типов данных в шаблонах функций
2343
2344
Вывод типов данных аргументов шаблонов практически всегда приемлем. Это 
2345
стандартный и ожидаемый вариант использования шаблона функции, потому что 
2346
шаблоны функций работают похоже на бесконечное множество перегрузок функции. 
2347
Как следствие, шаблоны функций почти всегда разрабатываются так, чтобы вывод 
2348
типов аргументов шаблона был понятен, безопасен или не компилировался вообще.
2349
2350
#### Вывод типов локальных переменных
2351
2352
Для локальных переменных допустимо использование вывода типов данных для того, 
2353
чтобы сделать код понятнее, путем удаления очевидной или нерелевантной 
2354
информации о типах данных, что позволяет читателю сосредоточиться на значимых 
2355
частях кода, например:
2356
2357
```c++
2358
std::unique_ptr<WidgetWithBellsAndWhistles> widget_ptr =
2359
    absl::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
2360
absl::flat_hash_map<std::string,
2361
                    std::unique_ptr<WidgetWithBellsAndWhistles>>::const_iterator
2362
    it = my_map_.find(key);
2363
std::array<int, 0> numbers = {4, 8, 15, 16, 23, 42};
2364
```
2365
2366
```c++
2367
auto widget_ptr = absl::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
2368
auto it = my_map_.find(key);
2369
std::array numbers = {4, 8, 15, 16, 23, 42};
2370
```
2371
2372
Бывает, что типы данных содержат смесь полезной информации и нефункционального
2373
кода, например `it` в примере выше: очевидно, что это итератор, и в большинстве 
2374
подобных случаев сам контейнер не имеет значения, то тип значения итератора, 
2375
вероятно, полезен. В подобных ситуациях часто возможно определить локальные 
2376
переменные, чьи явно указанные типы данных смогут донести важную информацию:
2377
2378
```c++
2379
auto it = my_map_.find(key);
2380
if(it != my_map_.end()) {
2381
    WidgetWithBellsAndWhistles& widget = *it->second;
2382
    // Do stuff with `widget`
2383
}
2384
```
2385
2386
Если тип - это шаблон класса, в котором параметры неважны, но сам по себе шаблон 
2387
- информативен, то можно использовать выведение 
2388
(параметров шаблона класса)[#вывод-аргументов-шаблонов-классов]. 
2389
2390
Не используйте `decltype(auto)` при наличии более простых альтернатив, т.к. 
2391
результат использования не всегда легко предсказуем.
2392
2393
#### Вывод типа возвращаемого значения
2394
2395
Используйте вывод типа возвращаемого значения (и для обычных, и для 
2396
лямбда-функций) только в том случае, если тело функции маленькое и содержит 
2397
небольшое количество `return`-выражений, потому что в противном случае будет 
2398
тяжело понять с первого взгляда, какой тип у возвращаемого значения функции. 
2399
Более того, у функции должна быть маленькая область видимости, потому что у 
2400
таких функций функции реализация определяет интерфейс, а не наоборот. Публичные 
2401
функции в заголовочных файлах никогда не должны использовать вывод типа 
2402
возвращаемого значения!
2403
2404
#### Вывод типов параметров
2405
2406
Ключевое слово `auto` в параметрах лямбда-функций стоит использовать с 
2407
осторожностью, поскольку в этом случае тип данных определяется кодом, который ее 
2408
вызывает, а не определением самой лямбда-функции. Соответственно, явное указание 
2409
типа, как правило, более понятно, за исключением тех случаев, когда 
2410
лямбда-функция вызывается очень близко к тому месту, где она была объявлена, 
2411
или лямбда-функция была передана настолько хорошо известному интерфейсу, что 
2412
очевидно, с какими аргументами она будет вызвана (например, `std::sort` в 
2413
примере выше).
2414
2415
#### Переменные захвата лямбда-функций
2416
2417
При инициализации переменных захвата предпочтительны 
2418
[специальные рекомендации](#лямбда-выражения), которые в целом подменяют общие 
2419
правила для использования вывода типов.
2420
2421
#### Структурные привязки
2422
2423
В отличие от других форм вывода типов данных, структурные привязки могут дать 
2424
читателю дополнительную информацию, если дать элементам большего объекта 
2425
правильные названия. Это значит, что объявление структурной привязки может 
2426
улучшить читаемость кода по сравнению с использованием явного типа даже в тех 
2427
случаях, когда использование `auto` не рекомендуется. Структурные привязки 
2428
особенно хорошо подходят при работе с парами или кортежами 
2429
(см. пример с `insert` выше), потому что у них не может быть содержательных 
2430
имен, но заметьте, что не стоит использовать 
2431
[кортежи и пары](#структуры-против-пар-и-кортежей), за исключением использования 
2432
имеющегося API, как в примере с `insert`.
2433
2434
Если объектом привязки является структура, иногда может быть полезно указать 
2435
имена, лучше подходящие для данного кода. Однако учитывайте, что они могут быть 
2436
менее понятны читателям кода, чем имена полей.
2437
2438
Рекомендуется использовать комментарии для указания имён полей, если они 
2439
отличаются от имён привязок. Используйте синтаксис, аналогичный комментариям к 
2440
параметрам функций:
2441
2442
```c++
2443
auto [/*field_name1=*/ bound_name1, /*field_name2=*/ bound_name2] = ...
2444
```
2445
2446
Также, как и с параметрами функций, комментарии могут помочь внешним 
2447
инструментам определить ошибки в порядке указания полей.
2448
2449
### Вывод аргументов шаблонов классов
2450
2451
Используйте вывод аргументов шаблонов класса только для тех шаблонов, которые 
2452
явно это поддерживают.
2453
2454
*Вывод аргументов шаблонов класса (Class Template Argument Deduction (CTAD))* 
2455
проявляется, когда переменная объявлена с типом шаблона, но без списка 
2456
аргументов (даже без угловых скобок):
2457
2458
```c++
2459
std::array a = {1, 2, 3}; // Тип `a`: std::array<int, 3>
2460
```
2461
2462
Компилятор выводит аргументы из выражения инициализации, используя 
2463
*правила вывода шаблона (template deduction guides)*, которые могут быть явными
2464
или неявными.
2465
2466
Явные правила вывода выглядят как объявления функции с возвращаемым значением в
2467
конце, но без ключевого слова `auto`, а название функции такое же, как и 
2468
название шаблона. Пример выше опирается на следующие правила вывода:
2469
2470
```c++
2471
namespace std {
2472
template <class T, class... U>
2473
array(T, U...) -> std::array<T, 1 + sizeof...(U)>;
2474
}
2475
```
2476
2477
Конструкторы в основном шаблоне (на в специализации) также определяют эти 
2478
правила, но неявно.
2479
2480
Когда происходит объявление переменной через CTAD, компиляторы выбирает правила
2481
подстановки, используя правила определения перегруженного конструктора, 
2482
возвращаемый тип правила становится типом переменной.
2483
2484
Иногда CTAD позволяет уменьшить количество формального кода.
2485
2486
Неявные правила CTAD, выводимые из конструктора могут привести к нежелательному 
2487
или совершенно некорректному поведению. Поскольку CTAD был представлен в C++17, 
2488
многие библиотеки, написанные до его появления, не учитывали принципы CTAD. 
2489
Более того, добавление явного описания правил вывода, чтобы исправить эту 
2490
проблему, может сломать код, который использует неявные.
2491
2492
Использование CTAD влечет те же проблемы, что и использование `auto`, потому что 
2493
обе эти семантики используют один и тот же механизм. CTAD дает пользователю 
2494
больше информации, чем `auto`, но также не дает явного указания, что 
2495
необходимая информация была опущена.
2496
2497
Не используйте CTAD в шаблонах классов до тех пор, пока разработчики не добавят 
2498
хотя бы одно явное объявление правил вывода шаблона (предполагается, что в 
2499
пространстве имён `std` CTAD поддерживается). Желательно, чтобы недопустимое 
2500
использование CTAD приводило к предупреждениям компилятора, если он это 
2501
поддерживает. 
2502
2503
### Лямбда-выражения
2504
2505
Используйте лямбда-выражения там, где это уместно. В тех случаях, когда 
2506
лямбда-функция выходит за пределы текущей области видимости, предпочтительно 
2507
использовать явный захват переменных.
2508
2509
Лямбда-выражения - это лаконичный способ создания анонимных объектов-функций. 
2510
Они часто полезны при передаче функции в виде аргумента. Например:
2511
2512
``` c++
2513
std::sort(v.begin(), v.end(), [](int x, int y) {
2514
    return weight(x) < weight(y);
2515
});
2516
```
2517
2518
Лямбда-функции позволяют захватывать переменные из окружающей области видимости 
2519
как явно, по имени, так и неявно, используя захват по-умолчанию. Для явного 
2520
захвата необходимо перечислить все требуемые переменные в виде значений или 
2521
ссылок:
2522
2523
```c++
2524
int weight = 3;
2525
int sum = 0;
2526
2527
// Захват `weight` по значению и `sum` по ссылке.
2528
std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
2529
    sum += weight * x;
2530
});
2531
```
2532
2533
Неявный захват по-умолчанию применяется ко всем переменным, используемым в теле 
2534
лямбда-функции, в том числе к `this`, если используются члены класса:
2535
2536
```c++
2537
const std::vector<int> lookup_table = ...;
2538
std::vector<int> indices = ...;
2539
2540
// Захват `lookup_table` по ссылке, сортировка `indices` по значению
2541
// ассоциированных элементов из `lookup_table`.
2542
std::sort(indices.begin(), indices.end(), [&](int a, int b) {
2543
    return lookup_table[a] < lookup_table[b];
2544
});
2545
```
2546
2547
В захвате переменной можно использовать выражения инициализации, что может быть
2548
использовано при захвате перемещаемых переменных по значению или в других 
2549
случаях, когда обычные правила захвата не подходят:
2550
2551
```c++
2552
std::unique_ptr<Foo> foo = ...;
2553
[foo = std::move(foo)] () {
2554
...
2555
}
2556
```
2557
2558
Для такого захвата, часто называемого захват с инициализацией (init capture) или 
2559
генерализированный захват (generalized lambda capture) не нужен захват
2560
чего-либо из окружающей области видимости. Такой синтаксис - это полностью 
2561
обобщенный способ определить любые переменные в лямбда-функцию:
2562
2563
```c++
2564
[foo = std::vector<int>({1, 2, 3})] () {
2565
...
2566
}
2567
```
2568
2569
Тип такой переменной выводится с полным соответствием с правилами использования 
2570
`auto`.
2571
2572
 * Лямбда-функции - это очень лаконичный способ определения объектов-функций для 
2573
 того, чтобы использовать из с алгоритмами из STL, что улучшает читаемость.
2574
 * Правильное использование неявного захвата может устранить избыточность и 
2575
 выявить важные исключения при захвате.
2576
 * Лямбда-функции, совместно с `std::function` и `std::bind` могут 
2577
 использоваться как обобщенный механизм обратного вызова (callback). Они 
2578
 упрощают разработку кода, который использует функции в качестве аргументов.
2579
2580
---
2581
2582
 * Захват переменных может быть источником ошибок, связанных с висячими 
2583
 ссылками, если лямбда-функция выходит за пределы текущей области видимости.
2584
 * Неявный захвате переменных по значению может вводить в заблуждение, 
2585
 поскольку приводит к проблеме висячих указателей. Захват указателей по 
2586
 значению не приводит к глубокому копированию объектов и часто приводит к тем 
2587
 же проблемам с областью видимости, что и захват переменных по ссылке. Это 
2588
 особенно запутывает, при получении `this` по значению, поскольку использование 
2589
 `this` часто неявно.
2590
 * Захват переменных на самом деле создает новые переменные (неважно, имеются ли 
2591
 в захвате выражения инициализации или нет), но они совсем не похожи на любое 
2592
 объявление переменных в C++. В частности, нигде не указывается тип переменной, 
2593
 даже ключевое слово `auto` (есть возможность указать тип данных неявно, 
2594
 например, через приведение типов). Сложно даже понять, что это определения 
2595
 переменных.
2596
 * Использование лямбда-функций может затруднить понимание кода. Сложные, 
2597
 вложенные лямбда функции могут сделать код очень трудночитаемым.
2598
2599
_Вывод:_
2600
 * Используйте лямбда-функции в подходящих случаях, используйте форматирование, 
2601
 описанное [ниже](#формат-лямбда-выражений).
2602
 * Используйте явный захват переменных в том случае, если лямбда-функция может 
2603
 выйти за пределы текущей области видимости. Например, вместо:
2604
2605
   ``` c++
2606
   {
2607
       Foo foo;
2608
       ...
2609
       executor->Schedule([&] { this->frobnicate(foo); })
2610
       ...
2611
   }
2612
   // ПЛОХО! При беглом просмотре можно упустить, что лямбда использует 
2613
   // ссылку на foo и this (если frobnicate является членом класса).
2614
   // Если лямбда вызывается после возврата из текущей функции, то
2615
   // это приведёт к проблемам, т.к. foo и другие объекты могут быть
2616
   // уже разрушены.
2617
   ```
2618
   Лучше написать:
2619
   
2620
   ``` c++
2621
   {
2622
       Foo foo;
2623
       ...
2624
       executor->Schedule([&foo] { frobnicate(foo); })
2625
       ...
2626
   }
2627
   // ЛУЧШЕ - Компилятор выдаст ошибку, если frobnicate является методом класса.
2628
   // Также явно указано, что foo захватывается по ссылке.
2629
   ```
2630
 * Используйте захват по-умолчанию по ссылке (`[&]`), только если время жизни 
2631
 лямбда-функции явно короче чем у любой переменной.
2632
 * Используйте захват по-умолчанию по значению (`[=]`), только как средство 
2633
 захвата нескольких переменных для короткой лямбда-функции. 
2634
   Не рекомендуется писать лямбда-функции с объёмным и сложным кодом вместе с 
2635
   захватом по-умолчанию по значению.
2636
 * Используйте захват только для существующих переменных из текущей области 
2637
 видимости. Не используйте захват с выражением инициализации
2638
 только для того, чтобы дать переменным более понятные имена или чтобы изменить 
2639
 значения текущих имен. Вместо этого создайте новую переменную традиционным 
2640
 способом, а потом захватывайте их или сделайте обычную функцию.
2641
 * Изучите секцию про 
2642
 [вывод типов данных](#вывод-типов-данных-в-том-числе-auto).
2643
2644
### Шаблонное метапрограммирование
2645
 
2646
Избегайте сложного шаблонного метапрограммирования.
2647
2648
*Шаблонное метапрограммирование (template metaprogramming)* относится к 
2649
методикам, которые используют тот факт, что механизм 
2650
*конкретизации шаблона (template instantiation)* является полным по Тьюрингу и 
2651
может быть использовать для произвольных вычислений во времени компиляции.
2652
2653
Метапрограммирование позволит создавать очень гибкие, высокопроизводительные и 
2654
типобезопасные интерфейсы. Каркасы, как GoogleTest,
2655
`std::tuple`, `std::function`, `boost::spirit` будут невозможны без этого.
2656
2657
Методики, использующиеся в шаблонном метапрограммировании часто не до конца 
2658
понятны кому-либо, кроме экспертов языка. Код, использующий шаблоны сложным 
2659
образом, часто нечитаемый, и его трудно отлаживать и сопровождать.
2660
2661
Сообщения компилятора при использовании шаблонного метапрограммирования часто 
2662
скудны и малопонятны: Даже если сам интерфейс простой, сложные детали реализации 
2663
становятся видимыми, когда пользователь делает что-то неправильно.
2664
2665
Шаблонное метапрограммирование усложняет рефакторинг, поскольку затрудняет 
2666
работу утилит для рефакторинга. Во-первых, шаблонный код раскрывается во 
2667
множествах контекстов, и сложно проверить, что рефакторинг будет работать 
2668
нормально во всех случаях.
2669
Во-вторых, некоторые утилиты для рефакторинга работают с AST, которое отображает 
2670
код уже после конкретизации всех шаблонов.
2671
2672
_Вывод:_
2673
2674
Шаблонное метапрограммирование часто позволяет разрабатывать чистые и простые в 
2675
использовании интерфейсы, невозможные без использования данной технологии, но 
2676
часто есть соблазн сделать код заумным. Лучше использовать шаблоны в небольшом 
2677
количестве низкоуровневых компонентов, сложность поддержки которых бы 
2678
компенсировалась простотой их использования.
2679
2680
Подумайте дважды, прежде чем использовать метапрограммирования или другие 
2681
сложные техники, основанные на шаблонах: Может ли средний программист в команде 
2682
понять этот код настолько хорошо, чтобы чтобы сопровождать его после того, как 
2683
вы займетесь другими проектами. Сможет ли не C++-программист, читающий код, 
2684
понять, что он делает и сообщения об ошибках, которые возникнут при неправильном 
2685
использовании. Если используются рекурсивную конкретизацию шаблонов, списки
2686
типов, метафункции, шаблоны выражений или используется SFINAE или трюк с 
2687
`sizeof` для разрешения перегрузки функции — скорее всего вы зашли слишком 
2688
далеко.
2689
2690
Прилагайте усилия к минимизации и изоляции сложности, когда используете 
2691
шаблонное метапрограммирование. По возможности, скрывайте от пользователя код, 
2692
использующий метапрограммирование. Тщательно документируйте, как использовать 
2693
код, на что будет похож "сгенерированный" код. Обратите внимание на сообщения об 
2694
ошибках, которые выдает компилятор, когда пользователи будут совершать
2695
ошибки. Сообщений об ошибках - часть вашего интерфейса и ваш код должен быть 
2696
настроен для максимального удобства пользователя.
2697
2698
### Boost
2699
2700
Используйте только одобренные библиотеки из коллекции Boost.
2701
2702
*Boost* это популярная коллекция проверенных, бесплатных и открытых 
2703
библиотек C++.
2704
2705
В целом код Boost является высококачественным, портируемым и во многом 
2706
дополняет стандартную библиотеку C++, например, в таких областях как свойства 
2707
типов (*type_traits*) или улучшенные связыватели (*binder*).
2708
2709
Некоторые библиотеки Boost поощряют создание кода, который ухудшает 
2710
читаемость: используется метапрограммирование или другие продвинутые техники 
2711
на шаблонах, а также чрезмерно функциональный стиль.
2712
2713
_Вывод_
2714
2715
Чтобы читаемость кода оставалась высокой для всех, кто осуществляет его 
2716
поддержку, разрешены к использованию только некоторые библиотеки из коллекции 
2717
Boost. В настоящее время это:
2718
 * `boost/call_traits.hpp`
2719
 * `boost/compressed_pair.hpp`
2720
 * Boost Graph Library (BGL) из `boost/graph`, за исключением сериализации
2721
(`adj_list_serialize.hpp`) и параллельных/распределённых алгоритмов и структур
2722
данных (`boost/graph/parallel/*` и `boost/graph/distributed/*`).
2723
 * Property Map из `boost/property_map`, за исключением
2724
параллельных/распределённых (`boost/property_map/parallel/*`).
2725
 * `boost/iterator`
2726
 * Часть Polygon, которая работает с построением диаграмм Вороного и не
2727
   зависит от остальной части Polygon: `boost/polygon/voronoi_builder.hpp`,
2728
   `boost/polygon/voronoi_diagram.hpp`, и 
2729
   `boost/polygon/voronoi_geometry_type.hpp`
2730
 * `boost/bimap`
2731
 * `boost/math/distributions`
2732
 * `boost/math/special_functions`
2733
 * Функции нахождения корня из `boost/math/tools`
2734
 * `boost/multi_index`
2735
 * `boost/heap`
2736
 * flat-контейнеры библиотеки Container: `boost/container/flat_map` и
2737
 `boost/container/flat_set`
2738
 * `boost/intrusive`
2739
 * `boost/sort`
2740
 * `boost/preprocessor`
2741
2742
В настоящее время прорабатывается вопрос о добавлении других библиотек Boost в 
2743
этот список, так что он может в будущем дополняться. Скорее всего, дождемся 
2744
новой версии стиля то Google.
2745
2746
### Остальные возможности C++
2747
2748
Некоторые расширения современного C++, как и Boost, провоцирует писать плохо 
2749
читаемый код. Другие расширения дублируют функционал, который доступен через 
2750
существующие механизмы, что может привести к путанице и дополнительной 
2751
конвертации кода.
2752
2753
Настоятельно не рекомендуется использовать следующие возможности C++:
2754
 * Рациональные числа времени компиляции (`<ratio>`), т.к. за интерфейсом может 
2755
 стоять сложный шаблон.
2756
 * Заголовочные файлы `<cfenv>` и `<fenv.h>`, поскольку многие компиляторы не 
2757
 поддерживают корректную работу этого функционала.
2758
 * Заголовочный файл `<filesystem>`, который недостаточно протестирован, и 
2759
 подвержен уязвимостям в безопасности.
2760
2761
### Псевдонимы (Aliases)
2762
2763
Открытые псевдонимы можно использовать для упрощения работы пользователя API, 
2764
они должны быть хорошо задокументировали.
2765
2766
Есть несколько способов для создания имен, которые будут псевдонимами для 
2767
других сущностей:
2768
 
2769
```c++
2770
typedef Foo Bar;
2771
using Bar = Foo;
2772
using other_namespace::Foo;
2773
```
2774
2775
В новои коде использование ключевого слова `using` предпочтительнее, чем 
2776
`typedef`, потому что оно предоставляет более согласованный с остальным C++ 
2777
синтаксис и работает с шаблонами.
2778
2779
Как и другие объявления, псевдонимы, объявленные в заголовочном файле - это 
2780
часть открытого API, до тех пор, пока они не в определении функции, не в 
2781
закрытой секции класса, или не находятся во внутреннем пространстве имен. 
2782
Псевдонимы в других частях кода, как `.cpp`-файлы - это детали реализации и не 
2783
ограничиваются данными правилами.
2784
 
2785
 * Псевдонимы могут улучшить читаемость, упрощая сложные или слишком длинные 
2786
 имена.
2787
 * Псевдонимы могут уменьшить дублирование, объявляя в одном месте тип, который 
2788
 будет использоваться повторно, что *может* облегчить читаемость.
2789
2790
---
2791
2792
 * Публичные псевдонимы увеличивают количество сущностей в API, что увеличивает 
2793
 сложность.
2794
 * Клиентский код легко может начать полагаться на особенности открытых 
2795
 псевдонимов, что усложняет внесение изменений.
2796
 * Есть соблазн поместить в публичный API псевдоним, который должен 
2797
 использоваться только во внутренней реализации, что усложнит сопровождение.
2798
 * Псевдонимы увеличивают риск возникновения коллизий имен.
2799
 * Псевдонимы могут ухудшить читаемость, давая знакомым конструкциям незнакомые 
2800
 имена. 
2801
 * Псевдонимы типов создают неясный контракт в API: неясно, всегда ли псевдоним 
2802
 будет соответствовать указанному псевдониму, иметь такой же API, или его можно 
2803
 использовать только в определенных местах.
2804
2805
_Вывод:_
2806
Не вводите псевдонимы в открытый API только для облегчения кодирования в 
2807
реализации. Задача публичного псевдонима - облегчить написание клиентского кода.
2808
2809
При определении открытого псевдонима, документируйте, зачем нужно новое имя, 
2810
гарантируется ли, что под псевдонимом всегда будет этот же тип, или есть 
2811
какие-то ограничения для его использования. 
2812
Это укажет пользователю, может ли он считать типы взаимозаменяемыми или 
2813
следует следовать более специфическим правилам, что позволит реализации иметь 
2814
некоторую степень свободы.
2815
2816
Не объявляйте псевдонимы пространств имен в своем открытом API 
2817
(см. [Пространства имен](#пространства-имен).
2818
2819
Например, использование следующих псевдонимов задокументировано:
2820
2821
``` c++
2822
namespace mynamespace {
2823
2824
// Используется для хранения измерений. DataPoint может меняться с Bar* на 
2825
// другой внутренний тип, его следует трактовать как абстрактный указатель.
2826
using DataPoint = foo::Bar*;
2827
2828
// Набор измерений. Добавлен для удобства пользователя.
2829
using TimeSeries = 
2830
    std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>;
2831
} // namespace mynamespace
2832
```
2833
2834
А приведенных ниже - нет:
2835
2836
```c++
2837
namespace mynamespace {
2838
2839
// Плохо: непонятно, как это использовать.
2840
using DataPoint = foo::Bar*;
2841
using std::unordered_set; // Плохо: это для внутреннего удобства
2842
using std::hash; // Плохо: это для внутреннего удобства
2843
typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> 
2844
    TimeSeries;
2845
} // namespace mynamespace
2846
```
2847
2848
Локальные псевдонимы, созданные для удобства внутри `.cpp`-файлов, закрытых 
2849
секций классов, внутренних пространств имен - это совершенно нормально:
2850
2851
```c++
2852
// В .cpp файле
2853
using foo::Bar;
2854
```
2855
2856
## Соглашения об именовании
2857
2858
Наиболее важные правила стиля кодирования приходятся на именование. Вид имени 
2859
сразу же (без поиска объявления) говорит нам что это: тип, переменная, функция, 
2860
константа, макрос и т.д. Правила именования могут быть произвольными, 
2861
однако куда более важна их согласованность чем индивидуальные предпочтения. 
2862
Так что независимо от того, находите вы правила разумными или нет, 
2863
их необходимо соблюдать.
2864
2865
### Основные правила именования
2866
2867
Следует использовать имена, которые будут понятны даже людям, 
2868
~~обременённым лишь тремя классами образования~~ работающим в разных командах.
2869
2870
Имя должно говорить о назначении и применимости объекта. Не стоит заморачиваться 
2871
по поводу длины строк при выборе имени, поскольку более длинное и понятное имя 
2872
всегда лучше, чем короткое и непонятное. Стоит минимизировать использование 
2873
аббревиатур, значение которых может быть неизвестно человеку, не работающему над 
2874
проектом (в частности акронимы и инициализмы). Запрещается порождать 
2875
аббревиатуры путём исключения букв из слов. Допускается использование 
2876
общеизвестных аббревиатур (из глоссария, например). В целом, длина имени должна 
2877
соответствовать области видимости. Например, n - подходящее имя внутри функции в 
2878
5 строк, но как имя члена класса - коротковато.
2879
2880
_Хороший код:_
2881
``` cpp
2882
class MyClass 
2883
{
2884
public:
2885
    int countFooErrors(const std::vector<Foo>& foos) {
2886
        int n = 0;    // Чёткий смысл для небольшой области видимости
2887
        for(const auto& foo : foos) {
2888
            ...
2889
            ++n;
2890
        }
2891
        return n;
2892
    }
2893
    void doSomethingImportant() {
2894
        std::string fqdn = ...;    // Известная аббревиатура полного доменного  
2895
                                   // имени ( Fully Qualified Domain Name)
2896
    }
2897
private:
2898
    const int kMaxAllowedConnections = ...;    // Чёткий смысл для контекста
2899
};
2900
```
2901
2902
_Плохой код:_
2903
``` cpp
2904
class MyClass 
2905
{
2906
public:
2907
    int countFooErrors(const std::vector<Foo>& foos) {
2908
        int total_number_of_foo_errors = 0;    // Слишком подробное имя в контексте короткой функции
2909
        for(int foo_index = 0; foo_index < foos.size(); ++foo_index) {    // Лучше использовать `i`
2910
            ...
2911
            ++total_number_of_foo_errors;
2912
        }
2913
        return total_number_of_foo_errors;
2914
    }
2915
    void doSomethingImportant() {
2916
        int cstmr_id = ...;    // Сокращённое слово (удалены буквы)
2917
    }
2918
private:
2919
    const int kNum = ...;    // В контексте класса очень нечёткое имя
2920
};
2921
```
2922
2923
Отметим, что общепринятые сокращения и аббревиатуры также допустимы: `i` для 
2924
итератора или счётчика, `T` для параметра шаблона.
2925
2926
В дальнейшем будем считать, что "слово" - это всё, что пишется на английском 
2927
без пробелов, в том числе и аббревиатуры. Для имён, написанных в смешанном стиле 
2928
("camel case" или "Pascal case"), в которых первая буква каждого слова является 
2929
заглавной, следует относиться к аббревиатурам как к целому слову. Например, 
2930
предпочтительно использовать `StartRpc()` вместо `StartRPC()`.
2931
2932
Параметры шаблонов следуют правилом именования своих категорий: 
2933
[имена типов](#имена-типов) для типов, [имена переменных](#имена-переменных) 
2934
для переменных.
2935
2936
### Имена файлов
2937
2938
Имена файлов должны содержать только строчные буквы. В качестве разделителей 
2939
следует использовать подчёркивание (_) или дефис (-). Это зависит от выбранного 
2940
разделителя в проекте. Если нет единого подхода - используйте подчёркивание.
2941
2942
_Примеры подходящих имён:_
2943
* `my_useful_class.cpp`
2944
* `my-useful-class.cpp`
2945
* `myusefulclass.cpp`
2946
* `myusefulclass_test.cpp` - *_unittest и _regtest больше не используются*.
2947
2948
Файлы C++ должны иметь формат файла `.cpp`, а заголовочные - `.hpp`.
2949
Дополнительные файлы, подключаемые как текст, должны именоваться как .inc 
2950
(см. секцию 
2951
[Самодостаточные заголовочные файлы](#самодостаточные-заголовочные-файлы)).
2952
2953
Не используйте имена, которые уже представлены в `/usr/include`, 
2954
такие как `db.h`.
2955
2956
Старайтесь давать файлам специфичные имена. Например, `http_server_logs.hpp`
2957
лучше чем `logs.hpp`. Когда файлы используются парами, лучше давать им 
2958
одинаковые имена. Например, `foo_bar.hpp` и `foo_bar.cpp` (и содержат класс 
2959
`FooBar`).
2960
2961
### Имена типов
2962
2963
Имена типов начинаются с заглавной буквы, каждое новое слово также начинается с 
2964
заглавной. Подчёркивания не используются: `MyExcitingClass`, `MyExcitingEnum`.
2965
2966
Имена всех типов - классов, структур, псевдонимов, перечислений, параметров 
2967
шаблонов - именуются в одинаковом стиле.
2968
2969
``` cpp
2970
// классы и структуры
2971
class UrlTable { ...
2972
class UrlTableTester { ...
2973
struct UrlTableProperties { ...
2974
2975
// typedefs
2976
typedef hash_map<UrlTableProperties *, std::string> PropertiesMap;
2977
2978
// использование псевдонимов
2979
using PropertiesMap = hash_map<UrlTableProperties *, std::string>;
2980
2981
// перечисления
2982
enum UrlTableErrors { ...
2983
```
2984
2985
### Имена переменных
2986
2987
Имена переменных (включая параметры функций) и членов данных пишутся строчными 
2988
буквами с подчёркиванием между словами. Члены данных классов (не структур) 
2989
дополняются префиксом `m_` . Например: `a_local_variable` , 
2990
`a_struct_data_member` , `m_a_class_data_member`.
2991
2992
#### Имена обычных переменных
2993
2994
Например:
2995
``` cpp
2996
std::string table_name;    // OK - строчные буквы с подчёркиванием
2997
```
2998
``` cpp
2999
std::string tableName;   // Плохо - смешанный стиль
3000
```
3001
3002
#### Члены данных класса
3003
3004
Члены данных классов, статические и нестатические, именуются как обычные 
3005
переменные с добавлением префикса `m_`.
3006
3007
``` cpp
3008
class TableInfo {
3009
    ...
3010
private:
3011
    std::string m_table_name_;  // OK - префикс в начале
3012
    static Pool<TableInfo>* m_pool;  // OK.
3013
};
3014
```
3015
3016
#### Члены данных структуры
3017
3018
Члены данных структуры, статические и нестатические, именуются как обычные 
3019
переменные. К ним не добавляется префикс.
3020
3021
``` cpp
3022
struct UrlTableProperties {
3023
    std::string name;
3024
    int num_entries;
3025
    static Pool<UrlTableProperties>* pool;
3026
};
3027
```
3028
См. также [Структуры против классов](#структуры-против-классов), где описано 
3029
когда использовать структуры, а когда - классы.
3030
3031
### Имена констант
3032
3033
Переменные, объявленные с использованием `constexpr` или `const`, не меняются в 
3034
ходе выполнения программы. Их имена начинаются с символа "k", далее идёт имя в 
3035
смешанном стиле (прописные и строчные буквы). Подчёркивание может быть 
3036
использовано в редких случаях когда прописные буквы не могут использоваться для 
3037
разделения. Например:
3038
``` cpp
3039
const int kDaysInAWeek = 7;
3040
const int kAndroid8_0_0 = 24;  // Android 8.0.0
3041
```
3042
Все аналогичные константные объекты со статическим типом хранилища (т.е. 
3043
статические или глобальные, подробнее [тут](#область-видимости))именуются 
3044
так же. Это соглашение является необязательным для переменных в других типах 
3045
хранилища (например, автоматические константные объекты).
3046
3047
### Имена функций
3048
3049
Обычные функции именуются в *смешанном стиле(camel case)* (прописные и строчные 
3050
буквы); функции доступа к переменным (*accessor* и *mutator*) должны иметь 
3051
стиль, аналогичный целевой переменной. 
3052
Обычно имя функции начинается со строчной буквы, а каждое новое слово в имени 
3053
пишется с прописной буквы.
3054
``` cpp
3055
addTableEntry()
3056
deleteUrl()
3057
openFileOrDie()
3058
```
3059
Аналогичные правила применяются для констант в области класса или пространства 
3060
имён (namespace) которые представляют собой часть API и должны выглядеть как 
3061
функции (и то, что они не функции - некритично)
3062
3063
Accessor-ы и mutator-ы (функции get и set) могут именоваться наподобие 
3064
соответствующих переменных. Они часто соответствуют реальным переменным-членам, 
3065
однако это не обязательно. Например, int count() и void set_count(int count).
3066
3067
### Именование пространства имён (namespace)
3068
3069
Пространство имён называется только строчными буквами, отдельные слова 
3070
разделяются подчёркиванием `(_)`. Пространство имён верхнего уровня основывается 
3071
на названии проекта. Избегайте коллизий вложенных имён и хорошо известных имён 
3072
пространств верхнего уровня.
3073
Пространство имён верхнего уровня - это обычно название проекта или команды 
3074
(которая делала код). Код обычно располагается в директории (или поддиректории) 
3075
с именем, соответствующим пространству имён.
3076
Правило [не использовать аббревиатуры](#основные_правила_именования) применимы и
3077
к пространствам имён. Коду внутри вряд ли потребуется упоминание пространства 
3078
имён, поэтому аббревиатуры - это лишнее.
3079
Избегайте использования известных названий для вложенных пространств имён. 
3080
Коллизии между именами могут привести к сюрпризам при сборке. В частности, не 
3081
создавайте вложенных пространств имён с именем `std`. Рекомендуются уникальные 
3082
идентификаторы проекта (`websearch::index`, `websearch::index_util`) вместо 
3083
небезопасных к коллизиям `websearch::util`.
3084
Для внутренних пространств имён коллизии могут возникать при добавлении другого 
3085
кода (внутренние вспомогательные функции имеют свойство повторяться у разных 
3086
команд). В этом случае хорошо помогает использование имени файла для именования 
3087
пространства имён, например `websearch::index::frobber_internal` для 
3088
использования в `frobber.hpp`.
3089
3090
### Имена перечислений
3091
3092
Перечисления, как с ограничениями на область видимости , так и без, должны 
3093
именоваться либо как [константы](#имена-констант), либо как [макросы]
3094
(#имена-макросов). Т.е.: либо `kEnumName`, либо `ENUM_NAME`.
3095
3096
Предпочтительно именовать отдельные значения в перечислении как константы,
3097
однако, допустимо именовать как макросы. Имя самого перечисления: 
3098
`UrlTableErrors` и `AlternateUrlTableErrors` - это тип. Следовательно, 
3099
используется смешанный стиль.
3100
3101
``` cpp
3102
enum UrlTableErrors {
3103
    kOk = 0,
3104
    kErrorOutOfMemory,
3105
    kErrorMalformedInput,
3106
};
3107
enum AlternateUrlTableErrors {
3108
    OK = 0,
3109
    OUT_OF_MEMORY = 1,
3110
    MALFORMED_INPUT = 2,
3111
};
3112
```
3113
3114
Вплоть до января 2009 года стиль именования значений перечисления был как у 
3115
макросов. Это создавало проблемы дублирования имён макросов и значений 
3116
перечислений. Применение стиля констант решает проблему и в новом коде 
3117
предпочтительно использовать стиль констант. Однако, старый код нет 
3118
необходимости переписывать, пока нет проблем дублирования.
3119
3120
### Имена макросов
3121
3122
Вы ведь не собираетесь [определять макросы](#макросы-препроцессора)? 
3123
На всякий случай (если собираетесь), они должны выглядеть так: 
3124
`MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE`.
3125
3126
Пожалуйста прочтите как определять макросы. Обычно макросы не должны 
3127
использоваться. Однако если они вам абсолютно необходимы, именуйте их 
3128
прописными буквами с символами подчёркивания.
3129
3130
``` cpp
3131
#define ROUND(x) ...
3132
#define PI_ROUNDED 3.0
3133
```
3134
3135
### Исключения из правил именования
3136
3137
Если вам нужно именовать что-то, имеющее аналоги в существующем C или C++ коде, 
3138
то следуйте используемому в коде стилю.
3139
3140
``` cpp
3141
bigopen()
3142
    // имя функции, образованное от open()
3143
uint
3144
    // похож на стандартный тип
3145
bigpos
3146
    // struct или class , образованный от pos
3147
sparse_hash_map
3148
    // STL-подобная сущность; следуйте стилю STL
3149
LONGLONG_MAX
3150
    // константа, такая же как INT_MAX
3151
```
3152
3153
## Комментарии
3154
3155
Комментарии являются обязательными для кода (если вы планируете его читать). 
3156
Следующие правила описывают, что вы должны комментировать и как. 
3157
Но помните: хотя комментарии очень важны, идеальный код сам себя документирует. 
3158
Использование *говорящих* имён для типов и переменных намного лучше, чем 
3159
непонятные имена, которые потом требуется расписывать в комментариях.
3160
3161
Комментируйте код с учётом его следующих читателей: программистов, которым 
3162
потребуется разбираться в вашем коде. Учтите, что следующим читателем можете 
3163
стать вы сами!
3164
3165
### Стиль комментариев
3166
3167
Используйте либо `//` либо `/* */`, пока не нарушается единообразие.
3168
3169
Вы можете использовать либо `//` либо `/* */`, однако `//` - *намного*  
3170
предпочтительнее. Однако, всегда согласовывайте ваш стиль комментариев с уже 
3171
существующим кодом.
3172
3173
### Комментарии в шапке файла
3174
3175
Данный шаг не является обязательным, однако, стоит упомянуть. В шапку можно 
3176
поместить информацию о лицензии, авторах и содержимом файлов. К примеру, 
3177
в одном заголовочном файле описано несколько абстракций, будет неплохо описать, 
3178
как они связаны друг с другом.
3179
3180
### Комментарии класса
3181
3182
Объявление класса должно сопровождаться комментарием, оформленным по правилам 
3183
[Doxygen]({TODO:ВСТАВИТЬ_ССЫЛКУ}), и располагаться в заголовочном `.hpp`-файле. 
3184
В случае, если некие тонкости реализации класса заслуживают отдельного 
3185
разъяснения, комментарий с разъяснением следует расположить в `.cpp` файле.
3186
3187
Комментарий к классу должен быть достаточным для понимания: как и когда 
3188
использовать класс, дополнительные требования для правильного использования 
3189
класса. Описывайте, если требуется, ограничения (предположения) на синхронизацию 
3190
в классе. Если экземпляр класса может использоваться из разных потоков, 
3191
обязательно распишите правила многопоточного использования.
3192
3193
В комментарии к классу также можно привести короткие примеры кода, показывающие 
3194
как проще использовать класс.
3195
3196
Дублировать комментарии в обоих файлах **не нужно**.
3197
3198
### Комментарии функции
3199
3200
Комментарии к объявлению функции должны описывать использование функции 
3201
(кроме самых очевидных случаев). Комментарии к определению функции описывают 
3202
реализацию.
3203
3204
#### Объявление функции
3205
3206
Объявление каждой функции должно иметь комментарий прямо перед объявлением: что 
3207
функция делает и как ей пользоваться. Комментарий можно опустить, только если 
3208
функция простая и использование очевидно, например, функции получения значений 
3209
переменных. Старайтесь начинать комментарии в изъявительном наклонении 
3210
("Открывает файл"). Использование повелительного наклонение 
3211
("Открыть файл") - не рекомендуется. Комментарий описывает суть функции, 
3212
а не то, как она это делает.
3213
3214
В комментарии к объявлению функции обратите внимание на следующее:
3215
3216
* Что подаётся на вход функции, что возвращается в результате.
3217
* Для функции-члена класса: сохраняет ли экземпляр ссылки на аргументы, нужно ли 
3218
освобождать память.
3219
* Выделяет ли функция память, которую должен удалить вызывающий код.
3220
* Могут ли быть аргументы `nullptr`.
3221
* Алгоритмическая сложность функции.
3222
* Допустим ли одновременный вызов из разных потоков. Что с синхронизацией?
3223
3224
Однако не стоит разжёвывать очевидные вещи.
3225
3226
Когда документируйте перегружаемые функции, делайте основной упор на изменениях 
3227
по сравнению с исходной функцией. А если изменений нет (что бывает часто), то 
3228
дополнительные комментарии вообще не нужны.
3229
3230
Комментируя конструкторы и деструкторы, учитывайте, что читатель кода знает их 
3231
назначение. Поэтому комментарий типа "разрушает этот объект" - бестолковый. 
3232
Можете описывать, что конструктор делает с аргументами (например, изменение 
3233
владения на указатели) или какие именно операции по очистке делает деструктор. 
3234
Если всё и так понятно - ничего не комментируйте. Вообще, обычно деструкторы не 
3235
имеют комментариев (при объявлении).
3236
3237
Комментарий объявления функции также должен быть оформлен по правилам 
3238
[Doxygen]({TODO: Вставить ссылку на Doxygen}).
3239
3240
#### Определение функций
3241
3242
Если есть какие-то хитрости в реализации функции, то можно к определению 
3243
добавить объяснительный комментарий. В нём можно описать трюки с кодом, дать 
3244
обзор всех этапов вычислений, объяснить выбор той или иной реализации (особенно 
3245
если есть лучшие альтернативы). Можете описать принципы синхронизации кусков 
3246
кода (здесь блокируем, а здесь рыбу заворачиваем).
3247
3248
Отметим что вы не должны повторять комментарий из объявления функции из `.hpp` 
3249
файла и т.п. Можно кратко описать, что функция делает, однако основной упор 
3250
должен быть как она это делает.
3251
3252
### Комментарии к переменным
3253
3254
По хорошему, имя переменной должно сразу говорить что это и зачем, однако в 
3255
некоторых случаях требуются дополнительные комментарии.
3256
3257
#### Член данных класса
3258
3259
Назначение каждого члена класса должно быть очевидно. Если есть неочевидные 
3260
тонкости (специальные значения, завязки с другими членами, ограничения по 
3261
времени жизни) - всё это нужно комментировать. Однако, если типа и имени
3262
 достаточно - комментарии добавлять не нужно.
3263
3264
С другой стороны, полезными будут описания особых (и неочевидных) значений 
3265
(`nullptr` или -1). Например:
3266
``` cpp
3267
private:
3268
    // Используется для проверки выхода за границы
3269
    // -1 - показывает, что мы не знаем сколько записей в таблице
3270
    int m_num_total_entries;
3271
```
3272
3273
#### Глобальные переменные
3274
3275
Ко всем глобальным переменным следует писать комментарий о их назначении и 
3276
(если не очевидно) почему они должны быть глобальными. Например:
3277
3278
``` cpp
3279
// Общее количество тестов, прогоняемых в регрессионном тесте
3280
const int kNumTestCases = 6;
3281
```
3282
3283
### Комментарии к реализации
3284
3285
Комментируйте реализацию функции или алгоритма в случае наличия неочевидных, 
3286
интересных, важных кусков кода.
3287
3288
#### Описательные комментарии
3289
3290
Блоки кода, отличающиеся сложностью или нестандартностью, должны предваряться 
3291
комментарием.
3292
3293
#### Комментарии к аргументам функций
3294
3295
Когда назначение аргумента функции неочевидно, стоит рассмотреть следующие 
3296
варианты:
3297
* Если аргумент представляет собой фиксированное значение (literal constant), и 
3298
он используется в разных блоках кода (и подразумевается, что его значение везде 
3299
одно и то же), вам следует создать константу и явно использовать её.
3300
* По возможности измените сигнатуру функции для замены типа аргумента с bool на 
3301
перечисление enum. Это сделает аргумент самодокументированным.
3302
* Для функций, использующих несколько конфигурационных опций в аргументах, 
3303
можно создать отдельный класс (или структуру), объединяющий все опции. И 
3304
передавать в функцию экземпляр этого класса. Такой подход имеет несколько 
3305
преимуществ: опции обозначаются именами, что объясняет их назначение. 
3306
Уменьшается количество аргументов в функции - код легче писать и читать. 
3307
И если вам понадобится добавить ещё опций, менять сам вызов функции не придётся.
3308
* Вместо больших и сложных вложенных выражений используйте именованную 
3309
переменную.
3310
* В крайнем случае используйте комментарии в месте вызова для прояснения 
3311
назначения аргументов.
3312
3313
Рассмотрим примеры:
3314
``` cpp
3315
// И какое назначение аргументов?
3316
const DecimalNumber product = calculateProduct(values, 7, false, nullptr);
3317
```
3318
Попробуем причесать:
3319
``` cpp
3320
ProductOptions options;
3321
options.set_precision_decimals(7);
3322
options.set_use_cache(ProductOptions::kDontUseCache);
3323
const DecimalNumber product =
3324
    CalculateProduct(values, options, /*completion_callback=*/nullptr);
3325
```
3326
3327
#### Чего делать точно нельзя
3328
3329
Не объясняйте очевидное. В частности, не описывайте дословно, что делает код, 
3330
кроме случаев, когда его поведение неочевидно для читателя, 
3331
хорошо разбирающегося в C++. Вместо этого, можно описать зачем этот код делает 
3332
так (или вообще сделайте код самодокументированным).
3333
3334
Сравним:
3335
``` cpp
3336
// Ищем элемент в векторе.  <-- Плохо: очевидно же!
3337
auto iter = std::find(v.begin(), v.end(), element);
3338
if(iter != v.end()) {
3339
    process(element);
3340
}
3341
```
3342
3343
С этим:
3344
``` cpp
3345
// Обрабатывает (process) "element" пока есть хоть один
3346
auto iter = std::find(v.begin(), v.end(), element);
3347
if(iter != v.end()) {
3348
    process(element);
3349
}
3350
```
3351
3352
Самодокументированный код вообще не нуждается в комментариях. 
3353
Комментарий на код выше может быть вообще очевидным (и не нужным):
3354
``` cpp
3355
if(!isAlreadyProcessed(element)) {
3356
    process(element);
3357
}
3358
```
3359
3360
### Пунктуация, орфография и грамматика
3361
3362
Обращайте внимание на пунктуацию, орфографию и грамматику: намного проще читать 
3363
грамотно написанные комментарии.
3364
3365
Комментарии должны быть написаны как рассказ: с правильной расстановкой 
3366
прописных букв и знаков препинания. В большинстве случаев законченные 
3367
предложения легче понимаются, нежели обрывки фраз. Короткие комментарии, 
3368
например как построчные, могут быть менее формальными, но всё равно должны 
3369
следовать общему стилю.
3370
3371
Хотя излишнее внимание код-ревьюера к использованию запятых вместо точек с 
3372
запятой может слегка раздражать, очень важно поддерживать высокий уровень 
3373
читабельности и понятности кода. Правильная пунктуация, орфография и грамматика 
3374
этому очень сильно способствует.
3375
3376
### Комментарии `TODO`
3377
3378
Используйте комментарии `TODO` для временного кода или достаточно хорошего 
3379
(промежуточного, не идеального) решения.
3380
3381
Комментарий должен включать строку `TODO` (все буквы прописные), за ней имя, 
3382
адрес e-mail, ID дефекта или другая информация для идентификации разработчика и 
3383
сущности проблемы, для которой написан `TODO`. Цель такого описания - 
3384
возможность потом найти больше деталей. Наличие `TODO` с описанием не означает,
3385
что указанный программист исправит проблему. Поэтому, когда вы создаёте `TODO`, 
3386
обычно там указано Ваше имя.
3387
3388
``` cpp
3389
// TODO(kl@gmail.com): Используйте "*" для объединения.
3390
// TODO(Zeke) Изменить для связывания.
3391
// TODO(bug 12345): удалить функционал "Последний посетитель".
3392
```
3393
3394
Если ваш `TODO` имеет вид "В будущем сделаем по-другому", то указывайте либо 
3395
конкретную дату (`Исправить в ноябре 2005`), либо событие (`Удалить тот код, 
3396
когда все клиенты будут обрабатывать XML запросы`).
3397
3398
## Форматирование
3399
3400
Стиль кодирования и форматирования являются вещью произвольной, однако проект 
3401
намного легче управляется, если все следуют одному стилю. Хотя кто-то может не 
3402
соглашаться со всеми правилами (или пользоваться тем, чем привыкли), очень важно 
3403
чтобы все следовали единым правилам, чтобы легко читать и понимать чужой код.
3404
3405
Для корректного форматирования мы создали [[файл настроек для Qt Creator]].
3406
3407
### Длина строк
3408
3409
Длина строки кода не должна превышать 80 символов.
3410
3411
Это правило немного спорное, однако масса уже существующего кода придерживается 
3412
этого принципа, и мы также поддерживаем его.
3413
3414
Приверженцы правила утверждают, что строки длиннее не нужны, а постоянно 
3415
подгонять размеры окон утомительно. Кроме того, некоторые размещают окна с кодом 
3416
рядом друг с другом и не могут произвольно увеличивать ширину окон. При этом 
3417
ширина в 80 символов - исторический стандарт, зачем его менять?.
3418
3419
Другая сторона утверждает, что длинные строки могут улучшить читаемость кода. 
3420
80 символов - пережиток мэйнфреймов 1960-х. Современные экраны вполне могут 
3421
показывать более длинные строки.
3422
3423
_Вывод:_
3424
3425
80 символов - максимум.
3426
Строка может превышать предел в 80 символов если это:
3427
3428
* комментарий при разделении потеряет в понятности или лёгкости копирования. 
3429
Например, комментарий с примером команды или URL-ссылкой, длиннее 80 символов;
3430
* выражение с `include`;
3431
* [защита от повторного включения](#защита-от-повторного-включения);
3432
* `using`-декларация.
3433
3434
### Не-ASCII символы
3435
3436
Не-ASCII символы следует использовать как можно реже, кодировка должна быть 
3437
UTF-8.
3438
3439
Вы не должны помещать в код строки которые будут показываться пользователю 
3440
(даже английские), поэтому Не-ASCII символы должны быть редкостью. Однако, 
3441
в ряде случаев допустимо включать такие слова в код. Например, если код парсит 
3442
файлы данных (с неанглийской кодировкой), возможно включать в код национальные 
3443
слова-разделители. В более общем случае, код модульных тестов может содержать 
3444
национальные строки. В этих случаях следует использовать кодировку UTF-8, т.к. 
3445
она понятна большинству утилит (которые понимают не только ASCII).
3446
3447
Кодировка hex также допустима, особенно если она улучшает читаемость. 
3448
Например, `"\xEF\xBB\xBF"` или `u8"\uFEFF"` - неразрывный пробел нулевой длины в 
3449
*Unicode*, и который не должен отображаться в правильном UTF-8 тексте.
3450
3451
Используйте префикс `u8` чтобы литералы вида `\uXXXX` кодировались в UTF-8. 
3452
Не используйте его для строк, содержащих не-ASCII символы уже закодированные в 
3453
UTF-8 - можете получить корявый текст если компилятор не распознает исходный 
3454
код как UTF-8.
3455
3456
Избегайте использования символов C++11 `char16_t` и `char32_t` т.к. 
3457
они нужны для не-UTF-8 строк. По тем же причинам не используйте 
3458
`wchar_t` (кроме случаев работы с Windows API, использующий wchar_t).
3459
3460
### Пробелы против Табуляции
3461
3462
Используйте только пробелы для отступов. Размер отступа составляет 4 пробела.
3463
3464
Мы используем пробелы для отступов. Не используйте табуляцию в своём коде. Вам 
3465
стоит настроить свой редактор на вставку 4 пробелов при нажатии клавиши `Tab`.
3466
3467
### Объявления и определения функций
3468
3469
Тип возвращаемого значения, имя функции и её параметры должны быть размещены в 
3470
одной строке, если всё умещается. Слишком длинный список параметров можно 
3471
разбить на строки.
3472
3473
Пример правильного оформления функции:
3474
``` cpp
3475
ReturnType ClassName::functionName(Type par_name1, Type par_name2) {
3476
    doSomething();
3477
    ...
3478
}
3479
```
3480
В случае если одной строки мало:
3481
``` cpp
3482
ReturnType ClassName::reallyLongFunctionName(Type par_name1, Type par_name2,
3483
                                             Type par_name3) {
3484
    doSomething();
3485
    ...
3486
}
3487
```
3488
или, если первый параметр также не помещается:
3489
``` cpp
3490
ReturnType LongClassName::reallyReallyReallyLongFunctionName(
3491
        Type par_name1,  // Отступ 8 пробелов
3492
        Type par_name2,
3493
        Type par_name3) {
3494
    doSomething();  // Отступ 4 пробела
3495
    ...
3496
}
3497
```
3498
3499
Несколько замечаний:
3500
3501
* Выбирайте хорошие имена для параметров.
3502
* Имя параметра можно опустить, если он не используется в определении функции.
3503
* Если тип возвращаемого значения и имя функции не помещаются в одной строке, 
3504
тип оставьте на одной строке, имя функции перенесите на следующую. В этом 
3505
случае не делайте дополнительный отступ перед именем функции.
3506
* Открывающая круглая скобка всегда находится на одной строке с именем функции.
3507
* Не вставляйте пробелы между именем функции и открывающей круглой скобкой.
3508
* Не вставляйте пробелы между круглыми скобками и параметрами.
3509
* Открывающая фигурная скобка всегда в конце последней строки определения. 
3510
Не переносите её на новую строку.
3511
* Закрывающая фигурная скобка располагается либо на отдельной строке, либо на 
3512
той же строке, где и открывающая скобка.
3513
* Между закрывающей круглой скобкой и открывающей фигурной скобкой должен быть 
3514
пробел.
3515
* Старайтесь выравнивать все параметры.
3516
* Стандартный отступ - 4 пробела.
3517
* При переносе параметров на другую строку используйте отступ в 8 пробелов.
3518
3519
Можно опустить имя неиспользуемых параметров, если это очевидно из контекста:
3520
``` cpp
3521
class Foo {
3522
public:
3523
    Foo(const Foo&) = delete;
3524
    Foo& operator=(const Foo&) = delete;
3525
};
3526
```
3527
3528
Неиспользуемые параметры с неочевидным контекстом следует закомментировать в 
3529
определении функции:
3530
``` cpp
3531
class Shape {
3532
public:
3533
    virtual void rotate(double radians) = 0;
3534
};
3535
3536
class Circle : public Shape {
3537
public:
3538
    void rotate(double radians) override;
3539
};
3540
3541
void Circle::rotate(double /*radians*/) {}
3542
```
3543
``` cpp
3544
// Плохой стиль - если кто-то потом захочет изменить реализацию функции,
3545
// назначение параметра не ясно.
3546
void Circle::rotate(double) {}
3547
```
3548
3549
Атрибуты и макросы старайтесь использовать в начале объявления или определения 
3550
функции, до типа возвращаемого значения:
3551
``` cpp
3552
ABSL_MUST_USE_RESULT bool isOk();
3553
```
3554
3555
### Формат лямбда-выражений
3556
3557
Форматируйте параметры и тело выражения аналогично обычной функции, список 
3558
захватываемых переменных - как обычный список.
3559
3560
Для захвата переменных по ссылке не ставьте пробел между амперсандом (`&`) и 
3561
именем переменной.
3562
3563
``` cpp
3564
int x = 0;
3565
auto x_plus_n = [&x](int n) -> int { return x + n; }
3566
```
3567
3568
Короткие лямбды можно использовать напрямую как аргумент функции.
3569
3570
``` cpp
3571
std::set<int> blacklist = {7, 8, 9};
3572
std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1};
3573
digits.erase(std::remove_if(digits.begin(), digits.end(), [&blacklist](int i) {
3574
               return blacklist.find(i) != blacklist.end();
3575
             }),
3576
             digits.end());
3577
```
3578
3579
### Числа с плавающей точкой
3580
3581
Числа с плавающей точкой всегда должны быть с десятичной точкой и числами по 
3582
обе стороны от неё (даже в случае экспоненциальной нотации). Такой подход 
3583
позволяет улучшить читаемость: все числа с плавающей запятой будут в 
3584
одинаковом формате, не спутаешь с целым числом, и символы E/e экспоненциальной 
3585
нотации не примешь за шестнадцатеричные цифры. Помните, что число в 
3586
экспоненциальной нотации не является целым числом.
3587
3588
_Плохой пример:_
3589
``` cpp
3590
float f = 1.f;
3591
long double ld = -.5L;
3592
double d = 1248e6;
3593
```
3594
3595
_Хороший пример:_
3596
``` cpp
3597
float f = 1.0f;
3598
float f2 = 1;   // Также правильно
3599
long double ld = -0.5L;
3600
double d = 1248.0e6;
3601
```
3602
3603
### Вызов функции
3604
3605
Следует либо писать весь вызов функции одной строкой, либо размещать аргументы 
3606
на новой строке. И отступ может быть либо по первому аргументу, либо 8 пробелов. 
3607
Старайтесь минимизировать количество строк, размещайте по несколько аргументов 
3608
на каждой строке.
3609
3610
Формат вызова функции:
3611
``` cpp
3612
bool result = doSomething(argument1, argument2, argument3);
3613
```
3614
3615
Если аргументы не помещаются в одной строке, то следует разделить их на 
3616
несколько строк, и каждая следующая строка выравнивается по первому аргументу. 
3617
Не добавляйте пробелы между круглыми скобками и аргументами:
3618
3619
``` cpp
3620
bool result = doSomething(averyveryveryverylongargument1,
3621
                          argument2, argument3);
3622
```
3623
3624
Допускается размещать аргументы на нескольких строках с отступом в 8 пробелов:
3625
``` cpp
3626
if(...) {
3627
    ...
3628
    ...
3629
    if(...) {
3630
        bool result = doSomething(
3631
                argument1, argument2,  // Отступ 8 пробелов
3632
                argument3, argument4);
3633
        ...
3634
    }
3635
}
3636
```
3637
3638
Старайтесь размещать по несколько аргументов в строке, уменьшая количество строк 
3639
на вызов функции, если это не ухудшает читаемость. Некоторые считают, что 
3640
форматирование строго по одному аргументу в строке более читаемо и облегчает 
3641
редактирование аргументов. Однако, мы ориентируемся прежде всего на читателей 
3642
кода (не редактирование), поэтому предлагаем ряд подходов для улучшения 
3643
читаемости.
3644
3645
Если несколько аргументов в одной строке ухудшают читаемость(из-за сложности или 
3646
запутанности выражений, попробуйте создать для аргументов "говорящие" 
3647
переменные:
3648
3649
``` cpp
3650
int my_heuristic = scores[x] * y + bases[x];
3651
bool result = doSomething(my_heuristic, x, y, z);
3652
```
3653
3654
Или разместите сложный аргумент на отдельной строке и добавьте поясняющий 
3655
комментарий:
3656
``` cpp
3657
bool result = doSomething(scores[x] * y + bases[x],    // Небольшая эвристика
3658
                          x, y, z);
3659
```
3660
3661
Если в вызове функции ещё есть аргументы, которые желательно разместить на 
3662
отдельной строке - размещайте. Решение должно основываться улучшении 
3663
читаемость кода.
3664
3665
Иногда аргументы формируют структуру. В этом случае форматируйте аргументы 
3666
согласно требуемой структуре:
3667
3668
``` cpp
3669
// Преобразование с помощью матрицы 3x3
3670
my_widget.transform(x1, x2, x3,
3671
                    y1, y2, y3,
3672
                    z1, z2, z3);
3673
```
3674
3675
### Форматирование списка инициализации
3676
3677
Форматируйте список инициализации аналогично вызову функции.
3678
3679
Если список в скобках следует за именем (например, имя типа или переменной), 
3680
форматируйте {} как будто это вызов функции с этим именем. Даже если имени нет, 
3681
считайте что оно есть, только пустое.
3682
3683
``` cpp
3684
// Пример списка инициализации на одной строке.
3685
return {foo, bar};
3686
functioncall({foo, bar});
3687
std::pair<int, int> p{foo, bar};
3688
3689
// Когда хочется разделить на строки.
3690
someFunction(
3691
        {"assume a zero-length name before {"},
3692
        some_other_function_parameter);
3693
3694
SomeType variable{
3695
        some, other, values,
3696
        {"assume a zero-length name before {"},
3697
        SomeOtherType{
3698
                "Very long string requiring the surrounding breaks.",
3699
                some, other values},
3700
        SomeOtherType{"Slightly shorter string",
3701
                      some, other, values}};
3702
3703
SomeType variable{
3704
        "This is too long to fit all in one line"};
3705
3706
MyType m = {  // Here, you could also break before {.
3707
        superlongvariablename1,
3708
        superlongvariablename2,
3709
        {short, interior, list},
3710
        {interiorwrappinglist,
3711
         interiorwrappinglist2}};
3712
```
3713
3714
### Условия
3715
3716
В выражении `if`, включая дополнительные конструкции `else if` и `else`, пробел 
3717
ставится только между закрывающей круглой скобкой и открывающей фигурной. Между 
3718
круглыми скобками и их содержимым скобки не допускаются. Открывающая фигурная 
3719
скобка всегда отделяется пробелом от других конструкций в этой же строке.
3720
3721
``` cpp
3722
if(condition) {    // без пробелов внутри скобок
3723
    ...  // отступ 4 пробела
3724
} 
3725
else if(...) {    // 'else' находится на новой строке после закрывающей скобки
3726
    ...
3727
} 
3728
else {
3729
    ...
3730
}
3731
```
3732
``` cpp
3733
if(condition) {     // Хороший код - нет пробела после 'if' и один пробел перед {
3734
if(condition){      // Плохо - нет пробела перед {
3735
if (condition) {    // Плохо - пробел после 'if'
3736
if (condition){     // Дважды плохо
3737
```
3738
3739
Даже если у выражения `if` нет последующих `else if` или `else`, а сама 
3740
конструкция в итоге может уместиться на одной либо максимум двух строках, 
3741
исключать фигурные скобки из конструкции нежелательно.
3742
3743
Следующие примеры показывают, как делать _нельзя_:
3744
``` cpp
3745
// Плохо - условие в одну строку, хотя есть 'else'
3746
if(x) doThis();
3747
else doThat();
3748
3749
// Плохо - в конструкции IF присутствует ELSE, а скобки не везде
3750
if(condition)
3751
    foo;
3752
else {
3753
    bar;
3754
}
3755
3756
// Плохо - конструкция IF слишком длинная, чтобы исключить фигурные скобки
3757
if(condition)
3758
    // Comment
3759
    doSomething();
3760
3761
// Плохо - и условие разбито на несколько строк,
3762
// и конструкция длинная, а скобок нет
3763
if(condition1 &&
3764
   condition2)
3765
    DoSomething();
3766
```
3767
3768
### Циклы и `switch`-`case`
3769
3770
Конструкция `switch` может использовать скобки для блоков. Описывайте 
3771
нетривиальные переходы между вариантами. Скобки необязательны для циклов с одним 
3772
выражением. Пустой цикл должен использовать либо пустое тело в скобках или 
3773
`continue`.
3774
3775
Блоки `case` в `switch` могут как быть с фигурными скобками, так быть и без них
3776
(на ваш выбор). Если же скобки используются, используйте формат, описанный ниже.
3777
3778
Рекомендуется в `switch` делать секцию `default`. Это необязательно в случае 
3779
использования перечисления, да и компилятор может выдать предупреждение если 
3780
обработаны не все значения. Если секция `default` не должна выполняться, тогда 
3781
формируйте это как ошибку. Например:
3782
3783
``` cpp
3784
switch(var) {
3785
    case 0: {    // Отступ 4 пробела
3786
        ...      // Отступ 8 пробелов
3787
        break;
3788
    }
3789
    case 1: {
3790
        ...
3791
        break;
3792
    }
3793
    default: {
3794
        assert(false);
3795
    }
3796
}
3797
```
3798
3799
Переход с одной метки на следующую должен быть помечен атрибутом 
3800
`[[fallthrough]];`. Размещайте `[[fallthrough]];` в точке, где будет переход. 
3801
Исключение из этого правила - последовательные метки без кода, в этом случае 
3802
помечать ничего не нужно.
3803
3804
``` cpp
3805
switch(x) {
3806
    case 41:    // Без пометок
3807
    case 43:
3808
        if(dont_be_picky) {
3809
            // Используйте атрибут вместо (или совместно) с комментарием о 
3810
            // переходе
3811
            [[fallthrough]];
3812
        } 
3813
        else {
3814
            closeButNoCigar();
3815
            break;
3816
        }
3817
    case 42:
3818
        doSomethingSpecial();
3819
        [[fallthrough]];
3820
    default:
3821
        doSomethingGeneric();
3822
        break;
3823
}
3824
```
3825
3826
Скобки являются опциональными для циклов с одной операцией, однако лучше всегда 
3827
их использовать.
3828
3829
``` cpp
3830
for(int i = 0; i < kSomeNumber; ++i)
3831
    printf("I love you\n");
3832
3833
for(int i = 0; i < kSomeNumber; ++i) {
3834
    printf("I take it back\n");
3835
}
3836
```
3837
3838
Пустой цикл должен быть оформлен либо как пара скобок, либо как continue без 
3839
скобок. Не используйте одиночную точку с запятой.
3840
3841
``` cpp
3842
while(condition) {
3843
    // Повторять до получения false
3844
}
3845
3846
for(int i = 0; i < kSomeNumber; ++i) {}    // Хорошо. Если разбить на две 
3847
                                           // строки - тоже будет хорошо
3848
3849
while(condition) continue;    // Хорошо - continue указывает на отсутствие 
3850
                              // дополнительной логики
3851
3852
while(condition);    // Плохо - выглядит как часть цикла do/while
3853
```
3854
3855
### Указатели и ссылки
3856
3857
Не ставьте пробелы вокруг `'.'` и `'->'`. Оператор разыменования или взятия 
3858
адреса должен быть без пробелов.
3859
3860
Ниже приведены примеры правильного форматирования выражений с указателями и 
3861
ссылками:
3862
3863
``` cpp
3864
x = *p;
3865
p = &x;
3866
x = r.y;
3867
x = r->y;
3868
```
3869
3870
Отметим:
3871
3872
* `'.'` и `'->'` используются без пробелов.
3873
* Операторы `*` или `&` не отделяются пробелами.
3874
3875
При объявлении переменной или аргумента можно размещать '*' как к типу, так и к 
3876
имени:
3877
3878
``` cpp
3879
// Отлично, пробел до *, &
3880
char *c;
3881
const std::string &str;
3882
3883
// Отлично, пробел после *, &
3884
char* c;
3885
const std::string& str;
3886
```
3887
3888
Старайтесь использовать единый стиль в файле кода, при модификации существующего 
3889
файла применяйте используемое форматирование.
3890
3891
Допускается объявлять несколько переменных одним выражением. Однако не 
3892
используйте множественное объявление с указателями или ссылками - это может быть 
3893
неправильно понято.
3894
3895
``` cpp
3896
// Хорошо - читаемо
3897
int x, y;
3898
3899
int x, *y;  // Плохо - не используйте множественное объявление с & или *
3900
char * c;   // Плохо - пробелы с обеих сторон *
3901
const std::string & str;  // Плохо - пробелы с обеих сторон &
3902
```
3903
3904
### Логические выражения
3905
3906
Если логическое выражение превышает 
3907
[рекомендованную длину строки](#длина-строк), используйте единый подход к 
3908
разбивке выражения на строки.
3909
3910
В данном примере, логический оператор `&&` находится всегда в конце строки:
3911
``` cpp
3912
if(this_one_thing > this_other_thing &&
3913
   a_third_thing == a_fourth_thing &&
3914
   yet_another && last_one) {
3915
    ...
3916
}
3917
```
3918
3919
Отметим, что разбиение кода (согласно примеру) производится так, чтобы оператор 
3920
`&&` завершал строку. Такой стиль чаще используется в коде Google, хотя 
3921
расположение операторов в начале строки тоже допустимо. Также, можете добавлять 
3922
дополнительные скобки для улучшения читабельности. Учтите, что использование 
3923
операторов в виде пунктуации (такие как `&&` и `~`) более предпочтительно, что 
3924
использование операторов в виде слов `and` и `compl`.
3925
3926
### Возвращаемые значения
3927
3928
Нет нужды заключать выражения `return` в скобки.
3929
Используйте скобки в `return expr;` только если бы вы использовали их в 
3930
выражении вида `x = expr;`.
3931
3932
``` cpp
3933
return result;    // Простое выражение - нет скобок
3934
3935
// Скобки - Ок. Они улучшают читаемость выражения
3936
return (some_long_condition &&
3937
        another_condition);
3938
3939
return (value);    // Плохо. Например, вы бы не стали писать var = (value);
3940
return(result);    // Плохо. return - это не функция!
3941
```
3942
3943
### Инициализация переменных и массивов
3944
3945
Вы можете использовать `=`, `()` и `{}` на ваш выбор.
3946
3947
Следующие примеры корректны:
3948
3949
``` cpp
3950
int x = 3;
3951
int x(3);
3952
int x{3};
3953
std::string name = "Some Name";
3954
std::string name("Some Name");
3955
std::string name{"Some Name"};
3956
```
3957
3958
Будьте внимательны при использовании списка инициализации `{...}` для типа, у 
3959
которого есть конструктор с `std::initializer_list`. Компилятор предпочтёт 
3960
использовать конструктор `std::initializer_list` при наличии списка в фигурных 
3961
скобках. Заметьте, что пустые фигурные скобки `{}` - это особый случай и будет 
3962
вызван конструктор по-умолчанию (если он доступен). Для явного использования 
3963
конструктора без `std::initializer_list` применяйте круглые скобки вместо 
3964
фигурных.
3965
3966
``` cpp
3967
std::vector<int> v(100, 1);    // Вектор из сотни единиц
3968
std::vector<int> v{100, 1};    // Вектор из 2-х элементов: 100 и 1
3969
```
3970
3971
Также использование круглых скобок запрещает ряд преобразований целых типов 
3972
(преобразования с уменьшением точности). И можно получить ошибки компиляции, 
3973
что весьма удобно.
3974
3975
``` cpp
3976
int pi(3.14);    // Ок: pi == 3
3977
int pi{3.14};    // Ошибка компиляции: "сужающее" преобразование
3978
```
3979
3980
### Директивы препроцессора
3981
3982
Знак `#` (признак директивы препроцессора) должен находиться всегда в начале 
3983
строки.
3984
3985
Даже если директива препроцессора относится к вложенному коду, директивы пишутся 
3986
с начала строки.
3987
3988
``` cpp
3989
// Хорошо - директивы с начала строки
3990
    if(lopsided_score) {
3991
#if DISASTER_PENDING      // Корректно - начинается с начала строки
3992
        dropEverything();
3993
# if NOTIFY               // Пробелы после # - ок, но не обязательно
3994
        notifyClient();
3995
# endif
3996
#endif
3997
        backToNormal();
3998
    }
3999
```
4000
``` cpp
4001
// Плохо - директивы с отступами
4002
    if(lopsided_score) {
4003
        #if DISASTER_PENDING  // Неправильно! "#if" должна быть в начале строки
4004
        dropEverything();
4005
        #endif                // Неправильно! Не делайте отступ для "#endif"
4006
        backToNormal();
4007
    }
4008
```
4009
4010
### Форматирование классов
4011
4012
Размещайте секции в следующем порядке: `public`, `protected` и `private`. 
4013
Отступ не требуется.
4014
4015
Ниже описан базовый формат для класса (за исключением комментариев, см. 
4016
[Комментарии класса](#комментарии-класса)):
4017
``` cpp
4018
class MyClass : public OtherClass 
4019
{
4020
public:         // без отступов
4021
    MyClass();  // Обычный 4-х пробельный отступ
4022
    explicit MyClass(int var);
4023
    ~MyClass() {}
4024
4025
    void someFunction();
4026
    void someFunctionThatDoesNothing() {
4027
    }
4028
4029
    void set_some_var(int var) { m_some_var = var; }
4030
    int some_var() const { return m_some_var; }
4031
4032
private:
4033
    bool someInternalFunction();
4034
4035
    int m_some_var;
4036
    int m_some_other_var;
4037
};
4038
```
4039
4040
_Замечания:_
4041
4042
* Имя базового класса пишется в той же строке, что и имя наследуемого класса 
4043
(конечно, с учётом ограничения в 80 символов).
4044
* Ключевые слова `public:`, `protected:`, и `private:` расположены без 
4045
каких-либо отступов.
4046
* Перед каждым из этих ключевых слов должна быть пустая строка (за исключением 
4047
первого упоминания). Также в маленьких классах пустые строки можно опустить.
4048
* Не добавляйте пустую строку после этих ключевых слов.
4049
* Секция `public` должна быть первой, за ней `protected` и в конце секция `private`.
4050
* Порядок объявлений в каждой из этих секций рассмотрен 
4051
[тут (порядок объявления)](#порядок-объявления).
4052
4053
### Список инициализации конструктора
4054
4055
Списки инициализации конструктора могут быть как в одну строку, так и на
4056
 нескольких строках с 8-ми пробельным отступом.
4057
4058
Ниже представлены правильные форматы для списков инициализации:
4059
``` cpp
4060
// Всё в одну строку
4061
MyClass::MyClass(int var) : some_var_(var) {
4062
    doSomething();
4063
}
4064
4065
// Если сигнатура и список инициализации не помещается на одной строке,
4066
// нужно перенести двоеточие и всё что после него на новую строку
4067
MyClass::MyClass(int var)
4068
        : some_var_(var), some_other_var_(var + 1) {
4069
    doSomething();
4070
}
4071
4072
// Если список занимает несколько строк, то размещайте каждый элемент на
4073
// отдельной строке и всё выравниваем
4074
MyClass::MyClass(int var)
4075
        : some_var_(var),             // Отступ 8 пробелов
4076
          some_other_var_(var + 1) {  // Выравнивание по предыдущему
4077
    doSomething();
4078
}
4079
4080
// Как и в других случаях, фигурные скобки могут размещаться на одной строке
4081
MyClass::MyClass(int var)
4082
        : some_var_(var) {}
4083
```
4084
4085
### Форматирование пространств имён
4086
4087
Содержимое в пространстве имён пишется без отступа.
4088
4089
[Пространство имён](#пространства-имен) не добавляет отступов. Например:
4090
4091
``` cpp
4092
namespace {
4093
4094
void foo() {  // Хорошо. Без дополнительного отступа
4095
      ...
4096
}
4097
4098
}  // namespace
4099
```
4100
4101
Не делайте отступов в пространстве имён:
4102
4103
``` cpp
4104
namespace {
4105
4106
    // Плохо. Сделан отступ там, где не нужно
4107
    void foo() {
4108
        ...
4109
    }
4110
4111
}  // namespace
4112
```
4113
4114
При объявлении вложенных пространств имён, размещайте каждое объявление на 
4115
отдельной строке.
4116
4117
``` cpp
4118
namespace foo {
4119
namespace bar {
4120
```
4121
4122
Можно использовать новшество из C++17:
4123
4124
``` cpp
4125
namespace foo::bar {
4126
}
4127
```
4128
4129
### Горизонтальная разбивка
4130
4131
Используйте горизонтальную разбивку в зависимости от ситуации. Никогда не 
4132
добавляйте пробелы в конец строки.
4133
4134
#### Общие принципы
4135
``` cpp
4136
void f(bool b) {    // Перед открывающей фигурной скобкой всегда ставьте пробел
4137
    ...
4138
int i = 0;    // Обычно перед точкой с запятой нет пробела
4139
// Пробелы внутри фигурных скобок для списка инициализации можно 
4140
// добавлять на ваш выбор. 
4141
// Если вы добавляете пробелы, то ставьте их с обеих сторон
4142
int x[] = { 0 };
4143
int x[] = {0};
4144
4145
// Пробелы вокруг двоеточия в списках наследования и инициализации
4146
class Foo : public Bar 
4147
{
4148
public:
4149
    // Для inline-функции добавляйте 
4150
    // пробелы внутри фигурных скобок (кроме пустого блока)
4151
    Foo(int b) : Bar(), m_baz(b) {}    // Пустой блок без пробелов
4152
    void reset() { m_baz = 0; }    // Пробелы разделяют фигурные скобки и реализацию
4153
    ...
4154
```
4155
4156
Добавление разделительных пробелов может мешать при слиянии кода. Поэтому не 
4157
добавляйте разделительных пробелов в существующий код. Вы можете удалить 
4158
пробелы, если уже модифицировали эту строку. Или сделайте это отдельной 
4159
операцией (предпочтительно, чтобы с этим кодом при этом никто не работал).
4160
4161
#### Циклы и условия
4162
``` cpp
4163
if(b) {          // Пробел после ключевого слова в условии или цикле
4164
} 
4165
else {          // пробел после else
4166
}
4167
4168
while(test) {}   // Внутри круглых скобок обычно не ставят пробел
4169
4170
switch(i) {
4171
for(int i = 0; i < 5; ++i) {
4172
4173
// Циклы и условия могут могут внутри быть с пробелам. Но это редкость.
4174
// В любом случае, будьте последовательны
4175
switch( i ) {
4176
if( test ) {
4177
for( int i = 0; i < 5; ++i ) {
4178
4179
// В циклах после точки с запятой всегда ставьте пробел
4180
// Также некоторые любят ставить пробел и перед точкой с запятой, 
4181
// но это редкость
4182
for( ; i < 5 ; ++i) {
4183
    ...
4184
4185
// В циклы по диапазону всегда ставьте пробел до двоеточия и после
4186
for(auto x : counts) {
4187
    ...
4188
}
4189
4190
switch(i) {
4191
    case 1:         // Перед двоеточием в case нет пробела
4192
        ...
4193
    case 2: break;  // После двоеточия есть пробел, 
4194
                    // если дальше на той же строке идёт код
4195
```
4196
4197
#### Операторы
4198
``` cpp
4199
// Операторы присваивания всегда окружайте пробелами
4200
x = 0;
4201
4202
// Другие бинарные операторы обычно окружаются пробелами,
4203
// хотя допустимо умножение/деление записывать без пробелов.
4204
// Между выражением внутри скобок и самими скобками не вставляйте пробелы
4205
v = w * x + y / z;
4206
v = w*x + y/z;
4207
v = w * (x + z);
4208
4209
// Унарные операторы не отделяйте от их аргумента
4210
x = -5;
4211
++x;
4212
if (x && !y)
4213
    ...
4214
```
4215
4216
#### Шаблоны и приведение типов
4217
``` cpp
4218
// Не ставьте пробелы внутри угловых скобок (< и >),
4219
// перед <, между >( в приведении
4220
std::vector<std::string> x;
4221
y = static_cast<char*>(x);
4222
4223
// Пробелы между типом и знаком указателя вполне допустимы. 
4224
// Но смотрите на уже используемый формат кода
4225
std::vector<char *> x;
4226
```
4227
4228
### Вертикальная разбивка
4229
4230
Сведите к минимуму вертикальное разбиение.
4231
4232
Это больше принцип, нежели правило: не добавляйте пустых строк без особой 
4233
надобности. В частности, ставьте не больше 1-2 пустых строк между функциями, не 
4234
начинайте функцию с пустой строки, не заканчивайте функцию пустой строкой, и 
4235
старайтесь поменьше использовать пустые строки. Пустая строка в блоке кода 
4236
должна работать как параграф в романе: визуально разделять две идеи.
4237
4238
_Базовый принцип:_ чем больше кода поместится на одном экране, тем легче его 
4239
понять и отследить последовательность выполнения. Используйте пустую строку 
4240
исключительно с целью визуально разделить эту последовательность.
4241
4242
Несколько полезных замечаний о пустых строках:
4243
4244
* Пустая строка в начале или в конце функции не улучшит читаемость.
4245
* Пустые строки в цепочке блоков `if-else` могут улучшить читаемость.
4246
* Пустая строка перед строкой с комментарием обычно помогает читаемости кода - 
4247
новый комментарий обычно предполагает завершение старой мысли и начало новой 
4248
идеи. И пустая строка явно на это намекает.
4249
* Пустые строки сразу после объявления пространства имён или блока пространств 
4250
имён может улучшить читаемость за счёт визуального разделения более значимого 
4251
содержимого от организационных обёрток. В особенности, когда первое объявление 
4252
внутри пространства предваряется комментарием, это становится особым случаем 
4253
предыдущего правила, помогая "прицепить" комментарий к последующему объявлению.
4254
4255
## Исключения из правил
4256
4257
Соглашения по кодированию, описанные выше являются обязательными. Однако, как 
4258
и в любых правилах, иногда в них есть исключения, которые сейчас и обсудим.
4259
4260
### Существующий код, не соответствующий стилю
4261
4262
Допустимо отклоняться от правил, если производится работа с кодом, не 
4263
соответствующим этому руководству.
4264
4265
Если модифицируется код, написанный другим стилем, допустимо отклоняться от 
4266
требований этого руководства и использовать "местный" стиль, чтобы получить 
4267
согласованный код. Если сомневаетесь - спросите автора кода (или того, кто это 
4268
поддерживает). Помните, что *согласованность* включает также и текущий стиль 
4269
кода.
4270
4271
### Программирование под Windows
4272
4273
Программисты под Windows могут использовать особенный набор соглашений о 
4274
кодировании, основанный на стиле заголовочных файлов в Windows и другом коде от 
4275
Microsoft. Так как хочется сделать, чтобы код был понятным для всех, то 
4276
рекомендуется использовать единое руководство по стилю в C++, одинаковое для
4277
всех платформ.
4278
4279
Повторим несколько рекомендаций, которые отличают данное руководство от стиля 
4280
Windows:
4281
4282
* Не используйте венгерскую нотацию (например, именование целочисленной 
4283
переменной как `iNum`). Вместо этого используйте соглашения об именовании от 
4284
Google, включая расширение `.cpp` для файлов с исходным кодом.
4285
* Windows определяет собственные синонимы для базовых типов, такие как `DWORD`,
4286
`HANDLE` и др. Понятно, что при вызове Windows API рекомендуется использовать 
4287
именно их. И всё равно, старайтесь определять типы, максимально похожие на C++. 
4288
Например, используйте `const TCHAR *` вместо `LPCTSTR`.
4289
* При компиляции кода с помощью Microsoft Visual C++ установите уровень 
4290
предупреждений 3 или выше. Также установите настройку, чтобы трактовать все 
4291
предупреждения как ошибки.
4292
* Вообще, не используйте нестандартные расширения, такие как `#pragma` и
4293
`__declspec` (исключение для случаев крайней необходимости). Использование 
4294
`__declspec(dllimport)` и `__declspec(dllexport)` допустимо, однако следует 
4295
оформить их как макросы `DLLIMPORT` и `DLLEXPORT`: в этом случае их можно легко 
4296
заблокировать, если код будет распространяться.
4297
4298
С другой стороны, есть правила, которые можно нарушать при программировании под 
4299
Windows:
4300
4301
* Обычно рекомендуется не использовать 
4302
[множественное наследование реализации](#наследование); однако это требуется 
4303
при использовании COM и некоторых классов ATL/WTL. В этом случае (при реализации
4304
 COM или ATL/WTL) нарушение правила допустимо.
4305
* Хотя использование исключений в собственном коде не рекомендуется, они 
4306
интенсивно используются в ATL и некоторых STL (в том числе и в варианте 
4307
библиотеки от Visual C++).
4308
* Типичный способ работы с 
4309
*прекомпилированными заголовочными файлами (precompiled headers)* - включить
4310
такой файл первым в каждый файл исходников, обычно с именем `StdAfx.h` или 
4311
`precompile.h`. Чтобы не создавать проблем при распространении кода, лучше 
4312
избегать явного включения такого файла (за исключением `precompile.cpp`). 
4313
Используйте опцию компилятора /FI для автоматического включения такого файла.
4314
* Заголовочный файлы ресурсов (обычно `resource.h`), содержащий только макросы, 
4315
может не следовать рекомендациям этого руководства.