Не паникуйте!
Найдите время, чтобы понять последствия применения правила руководства к вашей программе.
Эти руководящие принципы разработаны согласно принципу «подмножество надмножества» (Stroustrup05). Они не просто определяют подмножество C++ для использования (ради надёжности, безопасности, производительности и т.д.). Вместо этого они настоятельно рекомендуют использовать несколько простых «расширений» (компонентов библиотеки), которые делают ненужными наиболее подверженные ошибкам возможности C++, так что их можно запретить (в нашем наборе правил).
Правила акцентируют внимание на статической типобезопасности и безопасности ресурсов. По этой причине они подчёркивают возможности проверки диапазонов, избегания разыменования nullptr, избегания висячих указателей и системного использования исключений (через RAII). Отчасти для достижения этого, а отчасти для минимизации неясного кода как источника ошибок, правила также акцентируют внимание на простоте и сокрытии необходимой сложности за хорошо определёнными интерфейсами.
Многие правила носят предписывающий характер. Нам неудобно с правилами, которые просто гласят «не делайте этого!» без предложения альтернативы. Одним из следствий этого является то, что некоторые правила могут поддерживаться только эвристиками, а не точными и механически верифицируемыми проверками. Другие правила формулируют общие принципы. Для этих более общих правил более детальные и конкретные правила обеспечивают частичную проверку.
Эти руководящие принципы посвящены ядру C++ и его использованию. Мы ожидаем, что большинству крупных организаций, конкретных прикладных областей и даже крупных проектов потребуются дополнительные правила, возможно, дополнительные ограничения и дополнительная поддержка библиотек. Например, программисты жёстких систем реального времени, как правило, не могут свободно использовать свободное хранилище (динамическую память) и будут ограничены в выборе библиотек. Мы поощряем разработку таких более специфических правил в качестве дополнений к этим основным руководящим принципам. Создайте свою идеальную небольшую базовую библиотеку и используйте её, вместо того чтобы опускать уровень программирования до прославленного ассемблерного кода.
Правила разработаны с учётом возможности постепенного принятия.
Некоторые правила направлены на повышение различных форм безопасности, другие — на снижение вероятности ошибок; многие делают и то, и другое. Руководящие принципы, направленные на предотвращение ошибок, нередко запрещают вполне допустимый код C++. Однако когда есть два способа выразить идею, и один из них оказался распространённым источником ошибок, а другой — нет, мы стараемся направлять программистов ко второму.
In.not: Не-цели
Правила не претендуют на минимальность или ортогональность. В частности, общие правила могут быть простыми, но неприменимыми. Кроме того, зачастую сложно понять последствия применения общего правила. Более специализированные правила часто легче понять и применить, но без общих правил они представляли бы собой лишь длинный список частных случаев. Мы предоставляем правила как для помощи новичкам, так и для поддержки экспертного использования. Некоторые правила могут быть полностью применены, но другие основаны на эвристиках.
Эти правила не предназначены для последовательного чтения, как книга. Вы можете просматривать их по ссылкам. Однако их основное предназначение — служить целями для инструментов. То есть инструмент ищет нарушения и возвращает ссылки на нарушенные правила. Затем правила содержат обоснования, примеры возможных последствий нарушения и предлагаемые меры по устранению.
Эти руководящие принципы не предназначены для замены учебного курса по C++. Если вам нужен учебник для определённого уровня опыта, смотрите ссылки.
Это не руководство по преобразованию старого кода C++ в более современный. Оно призвано формулировать идеи для нового кода конкретным образом. Однако смотрите раздел о модернизации для получения некоторых возможных подходов к модернизации/обновлению/усовершенствованию. Важно отметить, что правила поддерживают постепенное принятие: как правило, нецелесообразно полностью переводить большую кодовую базу сразу.
Эти руководящие принципы не претендуют на полноту или точность в каждой языково-технической детали. За окончательным словом по вопросам определения языка, включая каждое исключение из общих правил и каждую возможность, обращайтесь к стандарту ISO C++.
Правила не направлены на то, чтобы заставить вас писать в обеднённом подмножестве C++. Они категорически не предназначены для определения, скажем, Java-подобного подмножества C++. Они не предназначены для определения единственного «истинного» языка C++. Мы ценим выразительность и безкомпромиссную производительность.
Правила не нейтральны в ценностях. Они призваны сделать код более простым и более правильным/безопасным, чем большинство существующего кода C++, без потери производительности. Они призваны препятствовать вполне допустимому коду C++, который коррелирует с ошибками, излишней сложностью и низкой производительностью.
Правила недостаточно точны для того, чтобы человек (или машина) мог следовать им, не думая. Разделы о применении стараются быть таковыми, но мы скорее оставим правило или определение несколько расплывчатым и открытым для интерпретации, чем сформулируем что-то точно и неверно. Иногда точность приходит только со временем и опытом. Проектирование ещё не является формой математики.
Правила не совершенны. Правило может причинить вред, запрещая что-то полезное в данной ситуации. Правило может причинить вред, не запрещая что-то, что допускает серьёзную ошибку в данной ситуации. Правило может причинить много вреда, будучи расплывчатым, неоднозначным, неприменимым или допуская любое решение проблемы. Невозможно полностью удовлетворить критерий «не навреди». Вместо этого наша цель скромнее: «Принести наибольшую пользу большинству программистов»; если вы не можете жить по правилу, возражайте против него, игнорируйте его, но не размывайте его до потери смысла. Также предлагайте улучшения.
In.force: Применение
Правила без применения неуправляемы для больших кодовых баз. Применение всех правил возможно только для небольшого слабого набора правил или для конкретного сообщества пользователей.
- Но мы хотим много правил, и мы хотим правил, которые каждый может использовать.
- Но у разных людей разные потребности.
- Но люди не любят читать много правил.
- Но люди не могут запомнить многие правила.
Таким образом, нам нужно подмножество для удовлетворения различных потребностей.
- Но произвольное подмножество приводит к хаосу.
Мы хотим руководящих принципов, которые помогают многим людям, делают код более единообразным и настоятельно побуждают людей модернизировать свой код. Мы хотим поощрять лучшие практики, а не оставлять всё на усмотрение отдельных лиц и давления руководства. Идеал — использовать все правила; это даёт наибольшую пользу.
Всё это складывается в немало дилемм. Мы стараемся решать их с помощью инструментов. Каждое правило имеет раздел Контроль, перечисляющий идеи по применению. Применение может осуществляться путём проверки кода, статического анализа, компилятора или проверок во время выполнения. По возможности мы предпочитаем «механическую» проверку (люди медленны, неточны и быстро устают) и статическую проверку. Проверки во время выполнения предлагаются редко, только там, где нет альтернативы; мы не хотим вводить «распределённое раздувание». Там, где это уместно, мы помечаем правило (в разделах Контроль) именем групп связанных правил (называемых «профилями»). Правило может входить в несколько профилей или ни в один. Для начала у нас есть несколько профилей, соответствующих общим потребностям (пожеланиям, идеалам):
- type: Без нарушений типов (переинтерпретация
TкакUчерез приведения, объединения или varargs) - bounds: Без нарушений границ (доступ за пределами диапазона массива)
- lifetime: Без утечек (отказ от
deleteили множественныйdelete) и без доступа к недопустимым объектам (разыменованиеnullptr, использование висячей ссылки).
Профили предназначены для использования инструментами, но также служат вспомогательным средством для читателя-человека. Мы не ограничиваем наши комментарии в разделах Контроль вещами, которые мы знаем, как применять; некоторые комментарии являются простыми пожеланиями, которые могут вдохновить разработчика инструментов.
Инструменты, реализующие эти правила, должны соблюдать следующий синтаксис для явного подавления правила:
[[gsl::suppress("tag")]]
и, при необходимости, с сообщением (согласно обычному синтаксису атрибутов стандарта C++11):
[[gsl::suppress("tag", justification: "message")]]
где
имя группы-профиля правил ("type", "bounds" или "lifetime"), или конкретное правило в профиле (type.4 или bounds.2). Любой текст, не являющийся одним из них, должен отклоняться.
"tag"— строковый литерал с именем якоря элемента, в котором появляется правило применения (например, для C.134 это "rh-public"),
"message"— строковый литерал
In.struct: Структура этого документа
Каждое правило (руководящий принцип, предложение) может содержать несколько частей:
Поскольку основные разделы по своей сути не упорядочены, мы используем буквы в качестве первой части «номера» ссылки на правило. Мы оставляем пробелы в нумерации, чтобы минимизировать «нарушение» при добавлении или удалении правил.
- Само правило — например, не используйте голый
new - Номер ссылки на правило — например, C.7 (7-е правило, связанное с классами).
- Причины (обоснования) — потому что программистам трудно следовать правилам, которые они не понимают
- Примеры — потому что правила трудно понять в абстрактном виде; могут быть положительными или отрицательными
- Альтернативы — для правил «не делайте этого»
- Исключения — мы предпочитаем простые общие правила. Однако многие правила применяются широко, но не универсально, поэтому исключения должны быть перечислены
- Контроль — идеи о том, как правило может быть проверено «механически»
- Смотрите также — ссылки на связанные правила и/или дальнейшее обсуждение (в этом документе или в других местах)
- Примечания (комментарии) — то, что нужно сказать, но не подходит под другие классификации
- Обсуждение — ссылки на более обширное обоснование и/или примеры, размещённые вне основных списков правил
Некоторые правила трудно проверить механически, но все они соответствуют минимальному критерию: опытный программист может обнаружить многие нарушения без особого труда. Мы надеемся, что «механические» инструменты со временем улучшатся, приближаясь к тому, что замечает такой опытный программист. Также мы предполагаем, что правила будут уточняться со временем, чтобы сделать их более точными и проверяемыми.
Правило нацелено на простоту формулировки, а не на тщательную проработку каждой альтернативы и каждого частного случая. Такая информация содержится в абзацах Альтернативы и разделах Обсуждение. Если вы не понимаете правило или не согласны с ним, пожалуйста, посетите его Обсуждение. Если вы считаете, что обсуждение отсутствует или неполно, создайте Issue, объясняющий ваши опасения, и, возможно, соответствующий PR.
Примеры написаны для иллюстрации правил.
Например, многие примеры являются языково-техническими и используют имена вроде f, base и x.
- Примеры не предназначены для промышленного качества или охвата всех учебных аспектов.
- Мы стараемся гарантировать, что «хорошие» примеры следуют Основным руководящим принципам.
- Комментарии часто иллюстрируют правила там, где они были бы излишними и/или отвлекающими в «реальном коде».
- Мы предполагаем знакомство со стандартной библиотекой. Например, мы используем просто
vector, а неstd::vector.
Это не языковое руководство. Оно призвано быть полезным, а не полным, полностью точным в технических деталях или руководством по существующему коду. Рекомендуемые источники информации можно найти в ссылках.
In.sec: Основные разделы
- In: Введение
- P: Философия
- I: Интерфейсы
- F: Функции
- C: Классы и иерархии классов
- Enum: Перечисления
- R: Управление ресурсами
- ES: Выражения и операторы
- Per: Производительность
- CP: Параллелизм и конкурентность
- E: Обработка ошибок
- Con: Константы и неизменяемость
- T: Шаблоны и обобщённое программирование
- CPL: Программирование в стиле C
- SF: Исходные файлы
- SL: Стандартная библиотека
Вспомогательные разделы:
- A: Архитектурные идеи
- NR: Не-правила и мифы
- RF: Ссылки
- Pro: Профили
- GSL: Библиотека поддержки руководящих принципов
- NL: Предложения по именованию и форматированию
- FAQ: Ответы на часто задаваемые вопросы
- Приложение A: Библиотеки
- Приложение B: Модернизация кода
- Приложение C: Обсуждение
- Приложение D: Вспомогательные инструменты
- Глоссарий
- К рассмотрению: Неклассифицированные прото-правила
Эти разделы не являются ортогональными.
Каждый раздел (например, «P» для «Философия») и каждый подраздел (например, «C.hier» для «Иерархии классов (ООП)») имеют аббревиатуру для удобства поиска и ссылок. Аббревиатуры основных разделов также используются в номерах правил (например, «C.11» для «Сделайте конкретные типы регулярными»).
P: Философия
Правила в этом разделе носят очень общий характер.
Краткое содержание философских правил:
- P.1: Выражайте идеи непосредственно в коде
- P.2: Пишите на стандартном ISO C++
- P.3: Выражайте намерение
- P.4: В идеале программа должна быть статически типобезопасной
- P.5: Предпочитайте проверку во время компиляции проверке во время выполнения
- P.6: То, что нельзя проверить во время компиляции, должно быть проверяемым во время выполнения
- P.7: Обнаруживайте ошибки времени выполнения как можно раньше
- P.8: Не допускайте утечек ресурсов
- P.9: Не тратьте впустую время и память
- P.10: Предпочитайте неизменяемые данные изменяемым
- P.11: Инкапсулируйте запутанные конструкции, а не разбрасывайте их по коду
- P.12: Используйте вспомогательные инструменты там, где это уместно
- P.13: Используйте вспомогательные библиотеки там, где это уместно
Философские правила, как правило, не поддаются механической проверке. Однако отдельные правила, отражающие эти философские темы, поддаются. Без философской основы более конкретные/специфические/проверяемые правила лишены обоснования.