Стандарты программирования на С++. 101 правило и рекомендация - страница 20
Понятно одно: в контексте статически типизированного языка С++, обеспечивающего строгую проверку типов и минимальную автоматическую проверку времени выполнения, программисты определенно должны использовать систему типов для своей пользы везде, где только это возможно (см. рекомендации с 90 по 100). В то же время тестирование времени выполнения целесообразно для выполнения проверок, зависящих от данных и потока выполнения программы (например, проверка выхода за границы массива или корректности входных данных) (см. рекомендации 70 и 71).
Имеется ряд примеров, где вы можете заменить проверки времени выполнения проверками времени компиляции.
Пример 1. Логические условия времени компиляции. Если вы проверяете логическое условие времени компиляции наподобие >sizeof(int) >= 8
, используйте статические проверки (обратите также внимание на рекомендацию 91).
Пример 2. Полиморфизм времени компиляции. Подумайте о замене полиморфизма времени выполнения (виртуальные функции) полиморфизмом времени компиляции (шаблоны) при определении обобщенных функций или типов. Последний приводит к коду с лучшей статической проверкой (см. также рекомендацию 64).
Пример 3. Перечисления. Подумайте об определении перечислений (или, что еще лучше, полностью законченных типов), когда вам требуется выразить символьные константы или ограниченные целочисленные значения.
Пример 4. Понижающее преобразование типов. Если вы часто используете оператор >dynamic_cast
(или, что еще хуже, непроверяемый >static_cast
) для понижающего преобразования типов, возможно, ваш базовый класс предоставляет слишком малую функциональность? Подумайте над перепроектированием ваших интерфейсов таким образом, чтобы ваша программа могла выразить необходимые вычисления посредством базового класса.
Некоторые условия не могут быть проверены в процессе компиляции и требуют проверки времени выполнения. В таком случае для обнаружения внутренних программных ошибок следует использовать >assert
(см. рекомендацию 68) и следовать советам из остальной части раздела, посвященного обработке ошибок, для прочих ошибок времени выполнения, таких как ошибки, зависящие от данных (см. рекомендации с 69 по 75).
[Alexandrescu01] §3 • [Boost] • [Meyers97] §46 • [Stroustrup00] §2.4.2 • [Sutter02] §4 • [Sutter04] §2, §19
15. Активно используйте >const
>const
— ваш друг: неизменяемые значения проще понимать, отслеживать и мотивировать, т.е. там, где это целесообразно, лучше использовать константы вместо переменных. Сделайте >const
описанием по умолчанию при определении значения — это безопасно, проверяемо во время компиляции (см. рекомендацию 14) и интегрируемо с системой типов С++. Не выполняйте преобразований типов с отбрасыванием >const
кроме как при вызове некорректной с точки зрения употребления >const
функции (см. рекомендацию 94).
Константы упрощают код, поскольку вам достаточно только один раз взглянуть на ее определение, чтобы знать, чему она равна везде. Рассмотрим такой код:
>void Fun(vector
> // ...
> const size_t len = v.size();
> // ... и еще 30 строк ...
>}
Увидев такое определение >len
, вы получаете надежную информацию о семантике этой константы в пределах области ее видимости (в предположении, что код не устраняет ее константность, чего он делать не должен, как вы узнаете далее): это информация о длине v в определенной точке программы. Взглянув на одну строку, вы получили всю необходимую информацию для всей области видимости. Если бы переменная >len
не была определена как >const
, она могла бы быть позже изменена — непосредственно или косвенно.
Заметим, что описание >const
не является глубоким. Чтобы понять что имеется в виду, рассмотрим класс >С
, который имеет член типа >X*
. В объекте >С
, который является константой, член >X*
также является константой, но сам объект >X
, на который он указывает, константой не является (см. [Saks99]).
Логическую константность следует реализовывать с использованием членов, описанных как >mutable
. Когда константная функция-член класса оправданно требует модификации переменной-члена (т.е. когда эта переменная не влияет на наблюдаемое состояние объекта, например, если это кэшированные данные), объявите эту переменную-член как