Главная страница Библиотека (скачать книги) Скачать софт Введение в программирование Стандарты для C++ Уроки по C# Уроки по Python HTML Веб-дизайн Ассемблер в среде Windows ActiveX Javascript Общее о Линукс Линукс - подробно Линукс - новое Delphi Паскаль для начинающих Турбопаскаль Новости Партнеры Наши предложения Архив новостей |
Стиль кодированияКонстанта для одного является переменной для другого.
В этом разделе мы перейдем от вопросов проектирования к вопросам, которые появляются в основном при реальном кодировании. Правила и рекомендации из этого раздела применимы безотносительно к конкретной области языка программирования (например, функциям, классам или пространствам имен), но приводят к повышению качества вашего кода. Многие из представленных идиом позволяют вашему компилятору активнее помогать вам в работе, а вам — избежать опасных мест (включая неопределенное поведение), которые компилятор не всегда в состоянии выявить. Все это делает ваш код более надежным. В этом разделе мы считаем наиболее важной рекомендацию 14: "Предпочитайте ошибки компиляции и компоновки ошибкам времени выполнения". 14. Предпочитайте ошибки компиляции и компоновки ошибкам времени выполненияРезюмеНе стоит откладывать до выполнения программы выявление ошибок, которые можно обнаружить при ее сборке. Предпочтительно писать код, который использует компилятор для проверки инвариантов в процессе компиляции, вместо того, чтобы проверять их во время работы программы. Проверки времени выполнения зависят от выполнимого кода и данных, так что вы только изредка можете полностью полагаться на них. Проверки времени компиляции, напротив, не зависят от данных и предыстории исполнения, что обычно обеспечивает более высокую степень надежности. ОбсуждениеЯзык C++ предлагает массу средств для "ускорения" обнаружения ошибок во время компиляции. Использование этих возможностей статических проверок дает массу преимуществ, включая следующие.
Один из наиболее мощных инструментов статических проверок в C++ — статическая проверка типов. Споры о том, должны ли типы проверяться статически (C++, Java, ML, Haskell) или динамически (Smalltalk, Ruby, Python, Lisp), все еще активно продолжаются. В общем случае нет явного победителя, и имеются языки и стили разработки, которые дают хорошие результаты как в одном, так и во втором случае. Сторонники статической проверки аргументируют свою позицию тем, что обработка большого класса ошибок времени выполнения может быть просто устранена, что дает более надежную и качественную программу. Поклонники динамических проверок говорят, что компиляторы способны выявить только часть потенциальных ошибок, так что если вы все равно должны писать тесты для ваших модулей, вы можете вообще не волноваться о статических проверках, получив при этом менее ограничивающую среду программирования. Понятно одно: в контексте статически типизированного языка C++, обеспечивающего строгую проверку типов и минимальную автоматическую проверку времени выполнения, программисты определенно должны использовать систему типов для своей пользы везде, где только это возможно (см. рекомендации с 90 по 100). В то же время тестирование времени выполнения целесообразно для выполнения проверок, зависящих от данных и потока выполнения программы (например, проверка выхода за границы массива или корректности входных данных) (см. рекомендации 70 и 71). ПримерыИмеется ряд примеров, где вы можете заменить проверки времени выполнения проверками времени компиляции.
ИсключенияНекоторые условия не могут быть проверены в процессе компиляции и требуют проверки времени выполнения. В таком случае для обнаружения внутренних программных ошибок следует использовать assert (см. рекомендацию 68) и следовать советам из остальной части раздела, посвященного обработке ошибок, для прочих ошибок времени выполнения, таких как ошибки, зависящие от данных (см. рекомендации с 69 по 75). 15. Активно используйте constРезюмеconst — ваш друг: неизменяемые значения проще понимать, отслеживать и мотивировать, т.е. там, где это целесообразно, лучше использовать константы вместо переменных. Сделайте const описанием по умолчанию при определении значения — это безопасно, проверяемо во время компиляции (см. рекомендацию 14) и интегрируемо с системой типов C++. Не выполняйте преобразований типов с отбрасыванием const кроме как при вызове некорректной с точки зрения употребления const функции (см. рекомендацию 94). ОбсуждениеКонстанты упрощают код, поскольку вам достаточно только один раз взглянуть на ее определение, чтобы знать, чему она равна везде. Рассмотрим такой код: void Fun( vector<int>& v ) { // ... const size_t len = v.size(); // ... и еще 30 строк ... } Увидев такое определение len, вы получаете надежную информацию о семантике этой константы в пределах области ее видимости (в предположении, что код не устраняет ее константность, чего он делать не должен, как вы узнаете далее): это информация о длине v в определенной точке программы. Взглянув на одну строку, вы получили всю необходимую информацию для всей области видимости. Если бы переменная Ten не была определена как const, она могла бы быть позже изменена — непосредственно или косвенно. Заметим, что описание const не является глубоким. Чтобы понять что имеется в виду, рассмотрим класс C, который имеет член типа X*. В объекте C, который является константой, член X* также является константой, но сам объект X, на который он указывает, константой не является . Логическую константность следует реализовывать с использованием членов, описанных как mutable. Когда константная функция-член класса оправданно требует модификации переменной-члена (т.е. когда эта переменная не влияет на наблюдаемое состояние объекта, например, если это кэшированные данные), объявите эту переменную-член как mutablе. Заметим, что если все закрытые члены скрыты с использованием идиомы Pimpl (см. рекомендацию 43), описание mutable не является необходимым ни для кэшированной информации, ни для неизменного указателя на нее. Модификатор const напоминает вирусное заболевание — появившись в вашем коде один раз, он приведет к необходимости соответствующего изменения сигнатур функций, которые еще не являются корректными в плане использования const. Это как раз не ошибка, а хорошее свойство, существенно увеличивающее мощь модификатора const, который еще не так давно был достаточно заброшен, а его возможности не вполне поняты и оценены. Переделка существующего кода для его корректности в плане использования const требует усилий, но они стоят того и даже позволяют выявить скрытые ошибки. Корректное применение const дает отличные результаты и повышает эффективность. Чрезвычайно важно правильно и последовательно использовать модификатор const в ваших программах. Понимание того, как и где изменяется состояние программы, особенно необходимо, а модификатор const по сути документирует непосредственно в коде программы, где именно компилятор может помочь вам в этом. Правильное употребление const поможет вам лучше разобраться с вопросами проектирования и сделать ваш код более надежным и безопасным. Если вы выяснили, что некоторую функцию-член невозможно сделать константной, значит, вы более детально разобрались с тем, как, где и почему эта функция модифицирует состояние объекта. Кроме того, вы сможете понять, какие члены-данные объединяют физическую и логическую константность (см. приведенные ниже примеры). Никогда не прибегайте к преобразованию константного типа в неконстантный, кроме случаев вызова функции, некорректной в плане использования модификатора const (не модифицирующей параметр, который тем не менее описан как неконстантный), а также такого редкого случая, как способ замены mutable в старом компиляторе, не поддерживающем эту возможность. ПримерыПример. Избегайте const в объявлениях функций, принимающих параметры по значению. Два следующих объявления абсолютно эквивалентны: void Fun( int x ); void Fun( const int x ); // Объявление той же самой функции: // const здесь игнорируется Во втором объявлении модификатор const избыточен. Мы рекомендуем объявлять функции без таких высокоуровневых модификаторов const, чтобы тот, кто читает ваши заголовочные файлы, не был дезориентирован. Однако использование такого модификатора имеет значение в определении функции и его применение может быть оправдано с точки зрения обнаружения непреднамеренного изменения переданного параметра: void Fun( const int x ) { // определение функции Fun // ... ++х; // Ошибка: нельзя изменять константное значение // ... } |
|
Библиотека программиста. 2009. |
|