Не делайте члены данных `protected`
Причина
protected-данные являются источником ошибок. protected-данные могут изменяться из неограниченного количества мест в различных частях кода. protected-данные — это аналог глобальных данных на уровне иерархии классов.
Пример
???
Альтернатива
RF: Ссылки
Для C++ написано множество стандартов кодирования, правил и руководств — особенно для специализированных областей применения C++. Многие из них
- сосредоточены на низкоуровневых вопросах, например на правописании идентификаторов
- написаны людьми, которые только начинают изучать C++
- рассматривают «предотвращение нестандартных действий программистов» как свою главную цель
- направлены на переносимость между множеством компиляторов (некоторые — десятилетней давности)
- написаны для сохранения кодовых баз, существующих десятки лет
- ориентированы на одну прикладную область
- откровенно контрпродуктивны
- игнорируются (программисты вынуждены их игнорировать, чтобы нормально работать)
Плохой стандарт кодирования хуже, чем отсутствие всякого стандарта. Однако подходящий набор рекомендаций значительно лучше, чем их полное отсутствие: «Форма освобождает».
Почему нельзя просто создать язык, который разрешает всё желаемое и запрещает всё нежелательное («идеальный язык»)? По существу — потому что доступные языки (и их инструментальные цепочки) также обслуживают людей с иными потребностями и покрывают больше сценариев, чем нужно вам сейчас. Кроме того, ваши потребности меняются со временем, и для адаптации нужен язык общего назначения. Язык, идеальный сегодня, окажется чрезмерно ограничивающим завтра.
Стандарты кодирования адаптируют использование языка под конкретные нужды. Поэтому единого стиля кодирования для всех не существует. Мы ожидаем, что различные организации будут добавлять собственные дополнения — как правило, с более жёсткими ограничениями и правилами стиля.
Разделы со ссылками:
- RF.rules: Правила кодирования
- RF.books: Книги с рекомендациями по кодированию
- RF.C++: Программирование на C++ (C++11/C++14/C++17)
- RF.web: Веб-сайты
- RS.video: Видео о «современном C++»
- RF.man: Руководства
- RF.core: Материалы Core Guidelines
RF.rules: Правила кодирования
???.
Особый упор делается на организацию и компоновку кода.
Ориентировано на C++03 и (в разумных пределах) несколько устаревшие подходы.
Ориентировано на C++17 и (также) на старые кодовые базы. Эксперты Google сейчас активно сотрудничают здесь, помогая улучшить данные Рекомендации, и, возможно, объединят усилия, чтобы сделать их современным общим стандартом, который они также могли бы рекомендовать.
Document Number 2RDU00001 Rev C. December 2005. Для программного обеспечения управления полётом. Для жёсткого реального времени. Это означает, что стандарт неизбежно очень строгий («если программа даёт сбой — кто-то погибнет»). Например, после взлёта самолёта не допускается никакого выделения или освобождения памяти из динамической кучи (никаких переполнений памяти и фрагментации). Запрещено использование исключений (поскольку не было инструментов, гарантирующих обработку исключения за фиксированное короткое время). Используемые библиотеки должны быть одобрены для критически важных приложений. Сходство с данным набором рекомендаций неудивительно, поскольку Бьёрн Страуструп был автором JSF++. Рекомендуется к изучению, но следует учитывать его очень специфическую направленность.
Как следует из названия, направлено на переносимость между многими (старыми) компиляторами. Ввиду этого носит ограничительный характер.
???.
???.
Тщательно проработанный набор правил (с примерами и обоснованиями) для кода, критичного с точки зрения безопасности. Многие из этих правил применимы в общем случае.
Несколько краткий, основан на C++14 и (вполне обоснованно) адаптирован к своей предметной области.
- AUTOSAR Guidelines for the use of the C++14 language in critical and safety-related systems v22.11 (устарело, заменено MISRA C++:2023)
- Boost Library Requirements and Guidelines.
- Bloomberg: BDE C++ Coding.
- Facebook: ???
- GCC Coding Conventions.
- Google C++ Style Guide.
- JSF++: JOINT STRIKE FIGHTER AIR VEHICLE C++ CODING STANDARDS.
- MISRA C++:2023 Guidelines for the use C++17 in critical systems.
- Using C++ in Mozilla Code.
- Geosoft.no: C++ Programming Style Guidelines.
- Possibility.com: C++ Coding Standard.
- SEI CERT: Secure C++ Coding Standard.
- High Integrity C++ Coding Standard.
- llvm.
- ???
RF.books: Книги с рекомендациями по кодированию
LCSD05. October 2005.
Addison-Wesley 2014. Каждая глава завершается разделом с советами, содержащим набор рекомендаций.
Addison-Wesley 2013. Каждая глава завершается разделом с советами, содержащим набор рекомендаций.
для Programming: Principles and Practice using C++. В основном низкоуровневые правила именования и компоновки. Прежде всего учебное пособие.
- Meyers96 Scott Meyers: More Effective C++. Addison-Wesley 1996.
- Meyers97 Scott Meyers: Effective C++, Second Edition. Addison-Wesley 1997.
- Meyers01 Scott Meyers: Effective STL. Addison-Wesley 2001.
- Meyers05 Scott Meyers: Effective C++, Third Edition. Addison-Wesley 2005.
- Meyers15 Scott Meyers: Effective Modern C++. O'Reilly 2015.
- SuttAlex05 Sutter and Alexandrescu: C++ Coding Standards. Addison-Wesley 2005. Скорее набор мета-правил, нежели конкретных правил. До C++11.
- Stroustrup05 Bjarne Stroustrup: A rationale for semantically enhanced library languages.
- Stroustrup14 Stroustrup: A Tour of C++.
- Stroustrup13 Stroustrup: The C++ Programming Language (4th Edition).
- Stroustrup: Style Guide
RF.C++: Программирование на C++ (C++11/C++14)
Подробное описание языка C++ и стандартных библиотек для опытных программистов.
Обзор языка C++ и стандартных библиотек для опытных программистов.
Учебник для начинающих и относительных новичков.
RF.web: Веб-сайты
- isocpp.org
- Домашние страницы Бьёрна Страуструпа
- WG21
- Boost<a name="Boost"></a>
- Adobe open source
- Poco libraries
- Sutter's Mill?
- ???
RS.video: Видео о «современном C++»
- Bjarne Stroustrup: C++11 Style. 2012.
- Bjarne Stroustrup: The Essence of C++: With Examples in C++84, C++98, C++11, and C++14. 2013
- Все доклады с CppCon ’14
- Bjarne Stroustrup: The essence of C++ в Эдинбургском университете. 2014.
- Bjarne Stroustrup: The Evolution of C++ Past, Present and Future. Пленарный доклад CppCon 2016.
- Bjarne Stroustrup: Make Simple Tasks Simple!. Пленарный доклад CppCon 2014.
- Bjarne Stroustrup: Writing Good C++14. Пленарный доклад CppCon 2015 о Core Guidelines.
- Herb Sutter: Writing Good C++14... By Default. Пленарный доклад CppCon 2015 о Core Guidelines.
- CppCon 15
- ??? C++ Next
- ??? Meting C++
- ??? more ???
RF.man: Руководства
- ISO C++ Standard C++11.
- ISO C++ Standard C++14.
- ISO C++ Standard C++17. Committee Draft.
- Palo Alto "Concepts" TR.
- ISO C++ Concepts TS.
- WG21 Ranges report. Draft.
RF.core: Материалы Core Guidelines
В этом разделе собраны материалы, оказавшиеся полезными при представлении основных рекомендаций и идей, лежащих в их основе:
и слайды. На русском языке. 2017.
Даёт некоторое представление об уровне амбиций, заложенных в Core Guidelines.
- Наш каталог документов
- Stroustrup, Sutter, and Dos Reis: A brief introduction to C++'s model for type- and resource-safety. Статья с многочисленными примерами.
- Sergey Zubkov: a Core Guidelines talk
- Neil MacIntosh: The Guideline Support Library: One Year Later. CppCon 2016.
- Bjarne Stroustrup: Writing Good C++14. Пленарный доклад CppCon 2015.
- Herb Sutter: Writing Good C++14... By Default. Пленарный доклад CppCon 2015.
- Peter Sommerlad: C++ Core Guidelines - Modernize your C++ Code Base. ACCU 2017.
- Bjarne Stroustrup: No Littering!. Bay Area ACCU 2016.
Обратите внимание, что слайды к докладам CppCon доступны (ссылки размещены вместе с видеозаписями).
Дополнения к этому списку приветствуются.
Благодарности
Благодарим всех, кто внёс вклад в виде правил, предложений, вспомогательных материалов, ссылок и т.д.:
- Peter Juhl
- Neil MacIntosh
- Axel Naumann
- Andrew Pardoe
- Gabriel Dos Reis
- Zhuang, Jiangang (Jeff)
- Sergey Zubkov
См. также список участников на github.
Pro: Профили
В идеале следовало бы придерживаться всех рекомендаций. Это дало бы наиболее чистый, регулярный, наименее подверженный ошибкам и зачастую самый быстрый код. К сожалению, это обычно невозможно, поскольку приходится встраивать свой код в большие кодовые базы и использовать существующие библиотеки. Зачастую такой код писался десятилетиями и не следует данным рекомендациям. Необходимо стремиться к постепенному внедрению.
Какую бы стратегию постепенного внедрения мы ни выбрали, нам нужна возможность применять наборы взаимосвязанных рекомендаций для решения одних проблем в первую очередь, откладывая остальные на потом. Аналогичная идея «взаимосвязанных рекомендаций» приобретает особое значение, когда только часть рекомендаций считается применимой к кодовой базе или когда для специализированной прикладной области требуется применить специальный набор рекомендаций. Такой набор взаимосвязанных рекомендаций мы называем «профилем». Мы стремимся к тому, чтобы такой набор рекомендаций был согласованным: его правила в совокупности должны помогать достичь конкретной цели, например «отсутствие ошибок выхода за пределы диапазона» или «статическая типобезопасность». Каждый профиль направлен на устранение определённого класса ошибок. Принудительное применение «случайных» правил по отдельности с большей вероятностью нарушит работу кодовой базы, нежели обеспечит ощутимое улучшение.
«Профиль» — это детерминированное и переносимо применимое подмножество правил (т.е. ограничений), предназначенное для достижения конкретной гарантии. «Детерминированное» означает, что правила требуют только локального анализа и могут быть реализованы в компиляторе (хотя и не обязательно). «Переносимо применимое» означает, что правила подобны языковым конструкциям — программисты могут рассчитывать на то, что различные инструменты принудительного применения дадут одинаковый ответ для одного и того же кода.
Код, написанный без предупреждений при использовании такого языкового профиля, считается соответствующим профилю. Соответствующий код считается безопасным по своей конструкции в отношении свойств безопасности, на которые нацелен данный профиль. Соответствующий код не будет первопричиной ошибок для данного свойства, хотя такие ошибки могут быть привнесены в программу другим кодом, библиотеками или внешней средой. Профиль также может вводить дополнительные типы библиотек для упрощения соответствия и поощрения правильного кода.
Сводка профилей:
В будущем мы планируем определить ещё больше профилей и добавить новые проверки в существующие. Кандидаты включают:
- сужающие арифметические повышения/преобразования (вероятно, часть отдельного профиля безопасной арифметики)
- арифметическое приведение из отрицательного числа с плавающей точкой к беззнаковому целому типу (аналогично)
- отдельные случаи неопределённого поведения: начать со списка UB Габриэля Дос Рейса, разработанного для исследовательской группы WG21
- отдельные случаи неуказанного поведения: решение проблем переносимости.
- нарушения
const: в основном уже обнаруживаются компиляторами, но можно выявлять неуместные приведения и недостаточное использованиеconst.
Активация профиля определяется реализацией; как правило, она задаётся в используемом инструменте анализа.
Чтобы отключить применение проверки профиля, разместите аннотацию suppress в языковом контракте. Например:
[[suppress("bounds")]] char* raw_find(char* p, int n, char x) // найти x в p[0]..p[n - 1]
{
// ...
}
Теперь raw_find() может произвольно работать с памятью. Очевидно, что подавление должно применяться крайне редко.
Pro.safety: Профиль типобезопасности
Этот профиль упрощает создание кода, который правильно использует типы и избегает непреднамеренного переосмысления типов (type punning). Достигается это путём устранения основных источников нарушений типов, включая небезопасное использование приведений и объединений.
Для целей данного раздела типобезопасность определяется как свойство, при котором переменная не используется способом, нарушающим правила для типа её определения. Память, к которой осуществляется доступ как к типу T, не должна содержать объект несвязанного типа U. Обратите внимание, что безопасность подразумевается полной только в сочетании с безопасностью границ и безопасностью времени жизни.
Реализация этого профиля должна распознавать следующие паттерны в исходном коде как несоответствующие и выдавать диагностику.
Сводка профиля типобезопасности:
- <a name="pro-type-avoidcasts"></a>Type.1: Избегайте приведений типов:
- <a name="pro-type-reinterpretcast"></a>Не используйте
reinterpret_cast; строгая версия правил Избегайте приведений и предпочитайте именованные приведения. - <a name="pro-type-arithmeticcast"></a>Не используйте
static_castдля арифметических типов; строгая версия правил Избегайте приведений и предпочитайте именованные приведения. - <a name="pro-type-identitycast"></a>Не приводите типы указателей, если исходный и целевой типы совпадают; строгая версия правила Избегайте приведений.
- <a name="pro-type-implicitpointercast"></a>Не приводите типы указателей, если преобразование может быть неявным; строгая версия правила Избегайте приведений.
Используйте вместо этого dynamic_cast.
Отдавайте предпочтение конструированию, именованным приведениям или T{expression}.
всегда инициализируйте, при необходимости используя конструкторы по умолчанию или инициализаторы членов по умолчанию.
Используйте вместо этого variant.
Не используйте аргументы va_arg.
- <a name="pro-type-downcast"></a>Type.2: Не используйте
static_castдля понижающего приведения: - <a name="pro-type-constcast"></a>Type.3: Не используйте
const_castдля снятияconst(то есть вообще): - <a name="pro-type-cstylecast"></a>Type.4: Не используйте приведения в стиле C
(T)expressionили функциональный стильT(expression): - <a name="pro-type-init"></a>Type.5: Не используйте переменную до её инициализации:
- <a name="pro-type-memberinit"></a>Type.6: Всегда инициализируйте член данных:
- <a name="pro-type-union"></a>Type.7: Избегайте голых объединений:
- <a name="pro-type-varargs"></a>Type.8: Избегайте varargs:
Влияние
С профилем типобезопасности можно доверять тому, что каждая операция применяется к допустимому объекту. Для сигнализирования об ошибках, которые невозможно обнаружить статически (во время компиляции), может быть брошено исключение. Обратите внимание, что полная типобезопасность достигается только при наличии также безопасности границ и безопасности времени жизни. Без этих гарантий к области памяти можно получить доступ независимо от того, какой объект, объекты или части объектов в ней хранятся.
Pro.bounds: Профиль безопасности границ
Этот профиль упрощает создание кода, работающего в пределах выделенных блоков памяти. Достигается это путём устранения основных источников нарушений границ: арифметики указателей и индексации массивов. Одна из ключевых особенностей этого профиля — ограничение указателей, которые должны ссылаться только на отдельные объекты, а не на массивы.
Мы определяем безопасность границ как свойство, при котором программа не использует объект для доступа к памяти за пределами выделенного для него диапазона. Безопасность границ подразумевается полной только в сочетании с типобезопасностью и безопасностью времени жизни, которые охватывают другие небезопасные операции, допускающие нарушения границ.
Сводка профиля безопасности границ:
Передавайте указатели только на отдельные объекты и Делайте арифметику указателей простой.
Передавайте указатели только на отдельные объекты и Делайте арифметику указателей простой.
Передавайте указатели только на отдельные объекты и Делайте арифметику указателей простой.
Используйте стандартную библиотеку типобезопасным образом.
- <a name="pro-bounds-arithmetic"></a>Bounds.1: Не используйте арифметику указателей. Используйте
spanвместо этого: - <a name="pro-bounds-arrayindex"></a>Bounds.2: Индексируйте массивы только с помощью константных выражений:
- <a name="pro-bounds-decay"></a>Bounds.3: Не допускайте неявного преобразования массива в указатель:
- <a name="pro-bounds-stdlib"></a>Bounds.4: Не используйте функции и типы стандартной библиотеки без проверки границ:
Влияние
Безопасность границ означает, что доступ к объекту — в частности к массивам — не выходит за пределы выделенной для него памяти. Это устраняет большой класс коварных и трудно обнаруживаемых ошибок, включая печально известные ошибки «переполнения буфера». Также закрываются бреши в безопасности и устраняется видный источник повреждения памяти (при записи за пределы границ). Даже если выход за границы является «всего лишь чтением», это может привести к нарушению инвариантов (если тип обращения не соответствует фактическому типу данных) и «таинственным значениям».
Pro.lifetime: Профиль безопасности времени жизни
Обращение через указатель, не указывающий ни на что, является одним из главных источников ошибок, которые очень трудно избежать при использовании многих традиционных стилей программирования на C или C++. Например, указатель может быть неинициализирован, равен nullptr, выходить за пределы массива или указывать на удалённый объект.
Текущую спецификацию дизайна смотрите здесь.
Сводка профиля безопасности времени жизни:
- <a name="pro-lifetime-invalid-deref"></a>Lifetime.1: Не разыменовывайте потенциально недействительный указатель:
Влияние
После полного применения посредством комбинации правил стиля, статического анализа и поддержки библиотек этот профиль
- устраняет один из главных источников неприятных ошибок в C++
- устраняет главный источник потенциальных уязвимостей безопасности
- повышает производительность за счёт устранения избыточных «параноидальных» проверок
- повышает уверенность в корректности кода
- исключает неопределённое поведение путём соблюдения ключевого правила языка C++
GSL: Библиотека поддержки рекомендаций
GSL — небольшая библиотека средств, предназначенных для поддержки данного набора рекомендаций. Без этих средств рекомендации были бы значительно более ограничивающими в отношении деталей языка.
Библиотека поддержки Core Guidelines определена в пространстве имён gsl, а имена могут быть псевдонимами для имён стандартной библиотеки или других широко известных библиотек. Использование (компилируемого) уровня косвенности через пространство имён gsl допускает эксперименты и создание локальных вариантов вспомогательных средств.
GSL является заголовочной библиотекой и расположена по адресу GSL: Guidelines support library. Средства вспомогательной библиотеки спроектированы как максимально лёгковесные (с нулевыми накладными расходами), чтобы не уступать по эффективности традиционным альтернативам. При необходимости они могут быть «инструментированы» дополнительными возможностями (например, проверками) для таких задач, как отладка.
В данных Рекомендациях используются типы как из стандарта (например, C++17), так и из GSL. Например, предполагается наличие типа variant, который в настоящее время отсутствует в GSL. В конечном счёте следует использовать вариант, принятый в C++17.
Некоторые из перечисленных ниже типов GSL могут не поддерживаться в используемой вами библиотеке по техническим причинам, связанным, например, с ограничениями текущих версий C++. Поэтому, пожалуйста, обратитесь к документации GSL для получения дополнительной информации.
Для каждого типа GSL ниже указан инвариант этого типа. Данный инвариант соблюдается до тех пор, пока пользовательский код изменяет состояние объекта GSL только с помощью предоставляемых типом функций-членов или свободных функций (то есть пользовательский код не обходит интерфейс типа для изменения значения/битов объекта в нарушение других правил Рекомендаций).
Сводка компонентов GSL:
- GSL.view: Представления
- GSL.owner: Указатели владения
- GSL.assert: Утверждения
- GSL.util: Утилиты
- GSL.concept: Концепции
Мы планируем создать полуформальную спецификацию GSL в «стиле стандарта ISO C++».
Мы опираемся на стандартную библиотеку ISO C++ и надеемся, что части GSL будут включены в стандартную библиотеку.
GSL.view: Представления
Эти типы позволяют пользователю различать владеющие и невладеющие указатели, а также указатели на отдельный объект и указатели на первый элемент последовательности.
Такие «представления» никогда не являются владельцами.
Ссылки никогда не являются владельцами (см. R.4). Примечание: у ссылок много возможностей пережить объекты, на которые они ссылаются (возврат локальной переменной по ссылке, хранение ссылки на элемент вектора при вызове push_back, привязка к std::max(x, y + 1) и т.д.). Профиль безопасности времени жизни призван решить эти проблемы, однако owner<T&> всё равно лишён смысла и не рекомендуется.
Имена преимущественно соответствуют стилю стандартной библиотеки ISO (строчные буквы и подчёркивание):
T*//T*не является владельцем, может быть null; предполагается указывающим на отдельный элемент.T&//T&не является владельцем и не может быть «нулевой ссылкой»; ссылки всегда привязаны к объектам.
Предполагается, что нотация «сырого указателя» (например, int*) имеет своё наиболее распространённое значение: указатель указывает на объект, но не владеет им. Владельцы должны быть преобразованы в дескрипторы ресурсов (например, unique_ptr или vector<T>) или помечены как owner<T*>.
owner<T*>//T*, владеющий объектом, на который указывает/ссылается; может бытьnullptr.
owner используется для пометки владеющих указателей в коде, который не может быть обновлён до использования надлежащих дескрипторов ресурсов. Причины для этого включают:
- Стоимость преобразования.
- Указатель используется совместно с ABI.
- Указатель является частью реализации дескриптора ресурса.
owner<T> отличается от дескриптора ресурса для T тем, что по-прежнему требует явного вызова delete.
Предполагается, что owner<T> ссылается на объект в свободной памяти (куче).
Если что-то не должно быть nullptr, укажите это явно:
T может быть любым типом, для которого ==nullptr имеет смысл.
not_null<T>//T— обычно тип указателя (например,not_null<int*>иnot_null<owner<Foo*>>), который не должен бытьnullptr.
span<T>//[p:p+n), конструктор из{p, q}и{p, n};T— тип указателяspan_p<T>//{p, predicate}[p:q), гдеq— первый элемент, для которогоpredicate(*p)истинно
span<T> ссылается на ноль или более изменяемых T, если только T не является const-типом. Все обращения к элементам span, в частности через operator[], гарантированно проверяются на выход за границы по умолчанию.
Примечание:
spanиз GSL (изначально называвшийсяarray_view) был предложен для включения в стандартную библиотеку C++ и был принят (с изменениями имени и интерфейса), за исключением того, чтоstd::spanне обеспечивает гарантированной проверки границ. Поэтому GSL изменил имя и интерфейсspanв соответствии сstd::span, и они должны быть полностью идентичны; единственное отличие состоит в том, чтоspanиз GSL по умолчанию является полностью безопасным по границам. Если безопасность границ может повлиять на его интерфейс, то соответствующие предложения об изменениях следует направить в комитет ISO C++ для обеспечения совместимости интерфейсаgsl::spanсstd::span. Если в будущем развитиеstd::spanдобавит проверку границ,gsl::spanможно будет удалить.
Арифметика с указателями лучше всего выполняется внутри span. char*, указывающий более чем на один char, но не являющийся C-строкой (например, указатель в буфер ввода), следует представлять с помощью span.
zstring//char*, предполагаемый C-строкой; то есть последовательностью символовchar, завершённой нулём, илиnullptrczstring//const char*, предполагаемый C-строкой; то есть последовательностью символовconst char, завершённой нулём, илиnullptr
Логически говоря, эти два последних псевдонима не нужны, но мы не всегда придерживаемся логики, и они делают явным различие между указателем на один char и указателем на C-строку. Последовательность символов, о которой не предполагается, что она завершена нулём, должна быть представлена как span<char> или, если это невозможно из-за проблем с ABI, как char*, а не zstring.
Используйте not_null<zstring> для C-строк, которые не могут быть nullptr. ??? Нужно ли нам имя для not_null<zstring>? или его «некрасивость» является достоинством?
GSL.owner: Указатели владения
Элементы изменяемы, если только T не является const-типом. По существу — span, который выделяет память и владеет своими элементами.
unique_ptr<T>// единоличное владение:std::unique_ptr<T>shared_ptr<T>// совместное владение:std::shared_ptr<T>(указатель со счётчиком ссылок)stack_array<T>// массив, размещённый на стеке. Число элементов определяется при конструировании и в дальнейшем фиксировано. Элементы изменяемы, если толькоTне являетсяconst-типом.dyn_array<T>// контейнер, динамически выделяемый массив без возможности роста. Число элементов определяется при конструировании и в дальнейшем фиксировано.
GSL.assert: Утверждения
// Expects(p) завершает программу, если только p == true // Expects управляется рядом параметров (принудительное применение, сообщение об ошибке, альтернативы завершению)
Expects// утверждение предусловия. В настоящее время размещается в телах функций. В дальнейшем должно быть перенесено в объявления.Ensures// утверждение постусловия. В настоящее время размещается в телах функций. В дальнейшем должно быть перенесено в объявления.
Эти утверждения в настоящее время являются макросами (увы!) и должны появляться только в определениях функций в ожидании решений комитета по стандарту относительно контрактов и синтаксиса утверждений. См. предложение по контрактам; при использовании синтаксиса атрибутов Expects(p) станет [[expects: p]].
GSL.util: Утилиты
finally//finally(f)создаётfinal_action{f}с деструктором, вызывающимfnarrow_cast//narrow_cast<T>(x)— этоstatic_cast<T>(x)narrow//narrow<T>(x)— этоstatic_cast<T>(x), еслиstatic_cast<T>(x) == xбез повышений знаковости, в противном случае бросаетnarrowing_error(например,narrow<unsigned>(-42)бросает исключение)[[implicit]]// «Маркер» для одноаргументных конструкторов, чтобы явно сделать их неявными.move_owner//p = move_owner(q)означаетp = q, но ???joining_thread// RAII-версияstd::thread, выполняющая join.index// тип для индексации контейнеров и массивов (в настоящее время псевдоним дляptrdiff_t)
GSL.concept: Концепции
Эти концепции (предикаты типов) заимствованы из библиотеки Origin Эндрю Саттона, предложения по диапазонам (Ranges) и технического отчёта ISO WG21 «Palo Alto». Многие из них весьма похожи на то, что стало частью стандарта ISO C++ в C++20.
StringNumberBooleanRange// в C++20:std::ranges::rangeSortable// в C++20:std::sortableEqualityComparable// в C++20:std::equality_comparableConvertible// в C++20:std::convertible_toCommon// в C++20:std::common_withIntegral// в C++20:std::integralSignedIntegral// в C++20:std::signed_integralSemiRegular// в C++20:std::semiregularRegular// в C++20:std::regularTotallyOrdered// в C++20:std::totally_orderedFunction// в C++20:std::invocableRegularFunction// в C++20:std::regular_invocablePredicate// в C++20:std::predicateRelation// в C++20:std::relation- ...
GSL.ptr: Концепции умных указателей
Pointer// Тип с операциями*,->,==и конструктором по умолчанию (предполагается, что конструктор по умолчанию устанавливает сингулярное «нулевое» значение)Unique_pointer// Тип, удовлетворяющийPointer, перемещаемый и некопируемыйShared_pointer// Тип, удовлетворяющийPointerи копируемый
NL: Рекомендации по именованию и компоновке
Последовательное именование и компоновка полезны. Хотя бы потому, что они минимизируют споры в духе «мой стиль лучше твоего». Однако существует очень много различных стилей, и люди страстно их отстаивают (как за, так и против). Кроме того, большинство реальных проектов включают код из множества источников, поэтому стандартизировать единый стиль для всего кода зачастую невозможно. После многочисленных просьб пользователей дать рекомендации, мы предлагаем набор правил, которые можно использовать при отсутствии лучших идей; однако подлинная цель — последовательность, а не конкретный набор правил. IDE и инструменты могут помочь (а могут и помешать).
Правила именования и компоновки:
- NL.1: Не описывайте в комментариях то, что ясно выражено в коде
- NL.2: Выражайте намерение в комментариях
- NL.3: Пишите лаконичные комментарии
- NL.4: Придерживайтесь единообразного стиля отступов
- NL.5: Избегайте кодирования информации о типах в именах
- NL.7: Делайте длину имени примерно пропорциональной длине его области видимости
- NL.8: Используйте единообразный стиль именования
- NL.9: Используйте
ALL_CAPSтолько для имён макросов - NL.10: Отдавайте предпочтение именам в стиле
underscore_style - NL.11: Делайте литералы читаемыми
- NL.15: Используйте пробелы экономно
- NL.16: Используйте принятый порядок объявления членов класса
- NL.17: Используйте компоновку, производную от K&R
- NL.18: Используйте компоновку объявлений в стиле C++
- NL.19: Избегайте имён, которые легко перепутать
- NL.20: Не размещайте два оператора на одной строке
- NL.21: Объявляйте только одно имя в одном объявлении
- NL.25: Не используйте
voidкак тип аргумента - NL.26: Используйте принятую нотацию
const - NL.27: Используйте суффикс
.cppдля файлов с кодом и.hдля файлов с интерфейсами
Большинство этих правил носит эстетический характер, и программисты придерживаются о них твёрдых мнений. IDE также, как правило, имеют настройки по умолчанию и ряд альтернативных вариантов. Эти правила предлагаются в качестве умолчаний, которым следует придерживаться при отсутствии оснований поступить иначе.
Мы получали комментарии в том духе, что именование и компоновка настолько личны и/или произвольны, что не следует пытаться «законодательно» их регулировать. Мы не «законодательствуем» (см. предыдущий абзац). Однако мы получали многочисленные просьбы предоставить набор соглашений по именованию и компоновке для использования в отсутствие внешних ограничений.
Более конкретные и детализированные правила проще применять принудительно.
Эти правила тесно связаны с рекомендациями PPP Style Guide, написанного в поддержку книги Страуструпа Programming: Principles and Practice using C++.