|
Программирование >> Решение нетривиальных задач
* Решение о переводе некоторых из идентификаторов, по меньшей мере, спорное. Однако, если вы не знаете английского, то будете лишены возможности оценить юмор автора, которым он оживил большую часть своих примеров. - Ред. имен, и эта возросшая общая сложность является определенным минусом. Если я использую функцию этим способом - как абстракцию -, то обычно объявляю ее одновременно статической, чтобы к ней нельзя было получить доступ снаружи текущего файла, и встроенной, чтобы ее вызов не приводил к накладным расходам. Не доводите процесс функционального абстрагирования до крайности. Мне доводилось видеть отличные программы, доведенные абстрагированием до полностью нечитаемого состояния такой степени, что нет ни одной функции длиннее, чем 5 или 6 строк. Получающаяся программа работает также значительно медленнее, чем необходимо, и ее исходный текст в 5 раз длиннее, чем нужно. 53.1. Код, используемый более одного раза, должен быть помещен в функцию Это правило является обратной стороной предыдущего. Если вы обнаруживаете почти идентичный код появляющимся более чем в одном месте своей программы, то этот код должен быть выделен в подпрограмму, которая вызывается из нескольких мест. Выгода состоит в меньшем размере программы и лучшей сопровождаемости вследствие упрощения программы и того, что вы должны теперь сопровождать лишь одну функцию; если вы находите ошибку, то вам нужно исправить ее только в одном месте. Как было упомянуто ранее, имя функции также дает хорошую абстракцию. Вызовы функции с хорошо выбранным именем являются обычно самодокументирующимися, устраняя необходимость в комментариях. 54. Функция должна иметь лишь одну точку выхода Это правило применимо лишь к программам на Си. Вообще, множество переходов goto к одной точке выхода лучше, чем много операторов return. Этим способом вы можете поместить точку прерывания у единственной точки выхода, вместо того, чтобы возиться с несколькими прерываниями. Например*: f() { int возвращаемое значение = ОШИБКА; if( некое условие ) ... возвращаемое значение = НЕЧТО; goto выход; else ... возвращаемое значение = НЕЧТО ЕЩЕ; goto выход; выход: return возвращаемое значение; Этот метод не срабатывает в Си++, потому что функции конструктора вызываются неявно в качестве части объявления; объявление часто скрывает вызов функции. Если вы пропускаете объявление, то вы пропускаете и вызов конструктора. Например, в следующей программе деструктор для x вызовется, а конструктор - нет: foo() { if( некое условие ) goto выход; некий класс x; Конструктор не вызывается. (Оператор goto перескакивает через него.) ... выход: Здесь вызывается деструктор для x при выходе x из области видимости. Вследствие этой проблемы лучше всего совсем избегать переходов goto в программах на Си++. 54.1. Всегда предусматривайте возврат значения из блока внешнего уровня Иногда, когда подпрограммы короткие, не стоит стараться обеспечить единственную точку выхода. (По моему мнению, правило избегай запутанности перекрывает любое другое правило, с которыми оно входит в конфликт). В этой ситуации всегда старайтесь убедиться, что из подпрограммы нет таких путей, которые не проходят через оператор return. Не так: if( a ) ... return делай что нужно(); else ... return ОШИБКА; а так: if( a ) ... return делай что нужно(); ... return ОШИБКА; В идеале, выход по ошибке организуется из внешнего уровня блока так, чтобы вы правильно обработали неожиданный аварийный выход на внешний уровень. 55. Избегайте дублирования усилий Следующий фрагмент демонстрирует эту проблему: if( strcmp(a, b) < 0 ) else if( strcmp(a, b) > 0 ) else if( strcmp(a, b) == 0 ) Вызов strcmp() в Си связан с немалыми накладными расходами (как в Паскале и других языках программирования), значительно лучше сделать так: int cmp = strcmp(a, b); if( cmp < 0 ) else if( cmp > 0 ) else остается случай cmp == 0
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |