- •Герб Саттер
- •Как пользоваться этой книгой
- •Стандарты кодирования и вы
- •Об этой книге
- •Благодарности
- •Вопросы организации и стратегии
- •0. Не мелочитесь, или Что не следует стандартизировать Резюме
- •Обсуждение
- •Примеры
- •1. Компилируйте без замечаний при максимальном уровне предупреждений Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •2. Используйте автоматические системы сборки программ Резюме
- •Обсуждение
- •3. Используйте систему контроля версий Резюме
- •Обсуждение
- •Исключения
- •Стиль проектирования
- •5. Один объект — одна задача Резюме
- •Обсуждение
- •Примеры
- •6. Главное — корректность, простота и ясность Резюме
- •Обсуждение
- •Примеры
- •7. Кодирование с учетом масштабируемости Резюме
- •Обсуждение
- •8. Не оптимизируйте преждевременно Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •10. Минимизируйте глобальные и совместно используемые данные Резюме
- •Обсуждение
- •Исключения
- •11. Сокрытие информации Резюме
- •Обсуждение
- •Исключения
- •13. Ресурсы должны быть во владении объектов Резюме
- •Обсуждение
- •Исключения
- •Стиль кодирования
- •14. Предпочитайте ошибки компиляции и компоновки ошибкам времени выполнения Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •Примеры
- •16. Избегайте макросов Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •17. Избегайте магических чисел Резюме
- •Обсуждение
- •Примеры
- •18. Объявляйте переменные как можно локальнее Резюме
- •Обсуждение
- •Исключения
- •Примеры
- •Исключения
- •Исключения
- •22. Минимизируйте зависимости определений и избегайте циклических зависимостей Резюме
- •Обсуждение
- •Исключения
- •Примеры
- •24. Используйте только внутреннюю, но не внешнюю защиту директивы #include Резюме
- •Обсуждение
- •Исключения
- •Функции и операторы
- •25. Передача параметров по значению, (интеллектуальному) указателю или ссылке Резюме
- •Обсуждение
- •26. Сохраняйте естественную семантику перегруженных операторов Резюме
- •Обсуждение
- •Исключения
- •27. Отдавайте предпочтение каноническим формам арифметических операторов и операторов присваивания Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •30. Избегайте перегрузки &&, || и , (запятой) Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •Проектирование классов и наследование
- •32. Ясно представляйте, какой вид класса вы создаете Резюме
- •Обсуждение
- •33. Предпочитайте минимальные классы монолитным Резюме
- •Обсуждение
- •34. Предпочитайте композицию наследованию Резюме
- •Обсуждение
- •Исключения
- •35. Избегайте наследования от классов, которые не спроектированы для этой цели Резюме
- •Обсуждение
- •36. Предпочитайте предоставление абстрактных интерфейсов Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •Исключения
- •Примеры
- •39. Виртуальные функции стоит делать неоткрытыми, а открытые — невиртуальными Резюме
- •Обсуждение
- •Исключения
- •Примеры
- •Исключения
- •41. Делайте данные-члены закрытыми (кроме случая агрегатов в стиле структур с) Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •42. Не допускайте вмешательства во внутренние дела Резюме
- •Обсуждение
- •Исключения
- •43. Разумно пользуйтесь идиомой Pimpl Резюме
- •Обсуждение
- •Исключения
- •Примеры
- •Исключения
- •Конструкторы, деструкторы и копирование
- •47. Определяйте и инициализируйте переменные-члены в одном порядке Резюме
- •Обсуждение
- •48. В конструкторах предпочитайте инициализацию присваиванию Резюме
- •Обсуждение
- •Исключения
- •Примеры
- •50. Делайте деструкторы базовых классов открытыми и виртуальными либо защищенными и невиртуальными Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •51. Деструкторы, функции освобождения ресурсов и обмена не ошибаются Резюме
- •Обсуждение
- •52. Копируйте и ликвидируйте согласованно Резюме
- •Обсуждение
- •Исключения
- •53. Явно разрешайте или запрещайте копирование Резюме
- •Обсуждение
- •54. Избегайте срезки. Подумайте об использовании в базовом классе клонирования вместо копирования Резюме
- •Обсуждение
- •Исключения
- •56. Обеспечьте бессбойную функцию обмена Резюме
- •Обсуждение
- •Исключения
- •Пространства имен и модули
- •57. Храните типы и их свободный интерфейс в одном пространстве имен Резюме
- •Обсуждение
- •Примеры
- •58. Храните типы и функции в разных пространствах имен, если только они не предназначены для совместной работы Резюме
- •Обсуждение
- •59. Не используйте using для пространств имен в заголовочных файлах или перед директивой #include Резюме
- •Обсуждение
- •Исключения
- •60. Избегайте выделения и освобождения памяти в разных модулях Резюме
- •Обсуждение
- •61. Не определяйте в заголовочном файле объекты со связыванием Резюме
- •Обсуждение
- •Исключения
- •62. Не позволяйте исключениям пересекать границы модулей Резюме
- •Обсуждение
- •63. Используйте достаточно переносимые типы в интерфейсах модулей Резюме
- •Обсуждение
- •Примеры
- •65. Выполняйте настройку явно и преднамеренно Резюме
- •Обсуждение
- •66. Не специализируйте шаблоны функций Резюме
- •Обсуждение
- •67. Пишите максимально обобщенный код Резюме
- •Обсуждение
- •Исключения
- •Обработка ошибок и исключения
- •68. Широко применяйте assert для документирования внутренних допущений и инвариантов Резюме
- •Обсуждение
- •Примеры
- •69. Определите разумную стратегию обработки ошибок и строго ей следуйте Резюме
- •Обсуждение
- •70. Отличайте ошибки от ситуаций, не являющихся ошибками Резюме
- •Обсуждение
- •Примеры
- •71. Проектируйте и пишите безопасный в отношении ошибок код Резюме
- •Обсуждение
- •Примеры
- •72. Для уведомления об ошибках следует использовать исключения Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •73. Генерируйте исключения по значению, перехватывайте — по ссылке Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •Исключения
- •Stl: контейнеры
- •76. По умолчанию используйте vector. В противном случае выбирайте контейнер, соответствующий задаче Резюме
- •Обсуждение
- •Примеры
- •77. Вместо массивов используйте vector и string Резюме
- •Обсуждение
- •78. Используйте vector (и string::c_str) для обмена данными с api на других языках Резюме
- •Обсуждение
- •79. Храните в контейнерах только значения или интеллектуальные указатели Резюме
- •Обсуждение
- •Примеры
- •80. Предпочитайте push_back другим способам расширения последовательности Резюме
- •Обсуждение
- •Исключения
- •81. Предпочитайте операции с диапазонами операциям с отдельными элементами Резюме
- •Обсуждение
- •Примеры
- •82. Используйте подходящие идиомы для реального уменьшения емкости контейнера и удаления элементов Резюме
- •Обсуждение
- •Исключения
- •Stl: алгоритмы
- •83. Используйте отладочную реализацию stl Резюме
- •Обсуждение
- •Примеры
- •84. Предпочитайте вызовы алгоритмов самостоятельно разрабатываемым циклам Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •85. Пользуйтесь правильным алгоритмом поиска Резюме
- •Обсуждение
- •86. Пользуйтесь правильным алгоритмом сортировки Резюме
- •Обсуждение
- •Примеры
- •Исключения
- •87. Делайте предикаты чистыми функциями Резюме
- •Обсуждение
- •Примеры
- •88. В качестве аргументов алгоритмов и компараторов лучше использовать функциональные объекты, а не функции Резюме
- •Обсуждение
- •89. Корректно пишите функциональные объекты Резюме
- •Обсуждение
- •Безопасность типов
- •90. Избегайте явного выбора типов — используйте полиморфизм Резюме
- •Обсуждение
- •Примеры
- •91. Работайте с типами, а не с представлениями Резюме
- •Обсуждение
- •92. Избегайте reinterpret_cast Резюме
- •Обсуждение
- •Исключения
- •93. Избегайте применения static_cast к указателям Резюме
- •Обсуждение
- •94. Избегайте преобразований, отменяющих const Резюме
- •Обсуждение
- •Исключения
- •95. Не используйте преобразование типов в стиле с Резюме
- •Обсуждение
- •96. Не применяйте memcpy или memcmp к не-pod типам Резюме
- •Обсуждение
- •97. Не используйте объединения для преобразований Резюме
- •Обсуждение
- •Исключения
- •99. Не используйте недействительные объекты и небезопасные функции Резюме
- •Обсуждение
- •100. Не рассматривайте массивы полиморфно Резюме
- •Обсуждение
- •Список литературы
- •Резюме из резюме
- •8. Не оптимизируйте преждевременно
- •15. Активно используйте const
- •23. Делайте заголовочные файлы самодостаточными
- •36. Предпочитайте предоставление абстрактных интерфейсов
- •61. Не определяйте в заголовочном файле объекты со связыванием
- •62. Не позволяйте исключениям пересекать границы модулей
- •63. Используйте достаточно переносимые типы в интерфейсах модулей
- •70. Отличайте ошибки от ситуаций, не являющихся ошибками
- •71. Проектируйте и пишите безопасный в отношении ошибок код
- •72. Для уведомления об ошибках следует использовать исключения
- •73. Генерируйте исключения по значению, перехватывайте — по ссылке
- •85. Пользуйтесь правильным алгоритмом поиска
- •86. Пользуйтесь правильным алгоритмом сортировки
- •87. Делайте предикаты чистыми функциями
- •88. В качестве аргументов алгоритмов и компараторов лучше использовать функциональные объекты, а не функции
Примеры
Клиентский код должен либо быть способен полиморфно удалять объекты посредством указателя на базовый класс, либо не должен этого делать. Каждый выбор определяет свой дизайн.
• Пример 1. Базовые классы с полиморфным удалением. Если должно быть разрешено полиморфное удаление, то деструктор должен быть открытым (в противном случае вызывающий код не сможет к нему обратиться) и должен быть виртуальным (в противном случае его вызов приведет к неопределенному поведению).
• Пример 2. Базовые классы без полиморфного удаления. Если полиморфное удаление не должно быть разрешено, деструктор должен не быть открытым (чтобы вызывающий код не мог к нему обратиться) и не должен быть виртуальным (потому что виртуальность ему не нужна).
Классы стратегий часто используются в качестве базовых для удобства, а не для обеспечения полиморфного поведения. Их деструкторы рекомендуется делать защищенными и невиртуальными.
Исключения
Некоторые компонентные архитектуры (например, COM или CORBA) не используют стандартный механизм удаления и применяют для этого различные собственные протоколы освобождения объектов. Следуйте шаблонам и идиомам этих архитектур и соответствующим образом адаптируйте данную рекомендацию.
Рассмотрим также еще один редкий случай.
• В одновременно является как базовым классом, так и конкретным классом, для которого могут создаваться объекты (так что деструктор этого класса должен быть открытым, чтобы было можно создавать и уничтожать объекты данного типа).
• У В нет виртуальных функций, и он не предназначается для полиморфного использования (так что хотя деструктор и открыт, он не обязан быть виртуальным).
Тогда несмотря на то, что деструктор оказывается открытым, имеется огромный соблазн не делать его виртуальным, поскольку такая первая виртуальная функция может привести к излишним расходам времени выполнения из-за добавления функциональности, которая нам совсем не нужна.
В этом редком случае вы можете сделать конструктор открытым и невиртуальным, но четко документировать, что производные объекты не могут использоваться полиморфно в качестве объектов базового класса. Именно это было сделано в случае класса std::unary_function.
В общем случае, однако, следует избегать конкретных базовых классов (см. рекомендацию 35). Например, unary_function представляет собой набор определений typedef, который не предназначен для создания объектов данного типа. В действительности бессмысленно давать ему открытый деструктор; лучше было бы последовать совету данной рекомендации и сделать его деструктор защищенным и невиртуальным.
Ссылки
[Cargill92] pp. 77-79, 207 • [Cline99] §21.06, 21.12-13 • [Henricson97] pp. 110-114 • [Koenig97] Chapters 4,11 • [Meyers97] §14 • [Stroustrup00] §12.4.2 • [Sutter02] §27 • [Sutter04] § 18
51. Деструкторы, функции освобождения ресурсов и обмена не ошибаются Резюме
Все запуски этих функций должны быть успешными. Никогда не позволяйте ошибке выйти за пределы деструктора, функции освобождения ресурса (например, оператора delete) или функции обмена. В частности, типы, деструкторы которых могут генерировать исключения, категорически запрещено использовать со стандартной библиотекой С++.