Главная - Литература

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 [128] 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

Пример использования счетчика безопасности для предотвращения бесконечной рекурсии (Visual Basic)

Public Sub RecursiveProc( ByRef safetyCounter As Integer ) If ( safetyCounter > SAFETY LIMIT ) Then

Exit Sub End If

safetyCounter = safetyCounter + 1

RecursiveProc( safetyCounter ) End Sub

В данном случае, если вложенность превысит предел счетчика безопасности, ре-к)фсия прекратится.

Если вы не хотите передавать счетчик безопасности в виде отдельного параметра, можно использовать классовую переменную в С++, Java, Visual Basic или соответствующий эквивалент в других языках.

Ограничьте рекурсию одним методом Циклическая рекурсия (А вызывает В вызывает С вызывает А) представляет опасность, потому что ее сложно обнаружить. Осмысление рекурсии в одном методе - достаточно трудоемкое занятие, а понимание рекурсии, охватывающей несколько методов, - это уже слишком. Если возникла циклическая рекурсия, обычно можно так перепроектировать методы, что рекурсия будет ограничена одним из них. Если это не получается, а вы все равно считаете, что рекурсия - это лучший подход, используйте счетчики безопасности в качестве страховки.

Следите за стеком При использовании рекурсии вы точно не знаете, сколько места в стеке будет занимать ваша программа. Кроме того, тяжело заранее предсказать, как будет вести себя программа во время выполнения. Однако вы можете предпринять некоторые усилия для контроля ее поведения.

Во-первых, если вы добавили счетчик безопасности, одним из принципов установки его предела является возможный размер используемого стека. Сделайте этот предел достаточно низким, чтобы предотвратить переполнение стека.

Во-вторых, следите за выделением памяти для локальных переменных в рекурсивных функциях, особенно если эти переменные достаточно объемны. Иначе говоря, лучше использовать new для создания объектов в куче, чем позволять компилятору генерировать автоматические объекты в стеке.

Не используйте рекурсию для факториалов и чисел Фибоначчи Одна из проблем с учебниками по вычислительной технике в том, что они предлагают глупые примеры рекурсии. Типичными примерами являются вычисление факториала или последовательности Фибоначчи. Рекурсия - мощный инструмент, и очень глупо использовать ее в этих двух случаях. Если бы программист, работающий у меня, применял рекурсию для вычисления факториала, я бы нанял кого-то другого. Вот рекурсивная версия вычисления факториала:



17.3. Оператор gofo

Вы могли думать, что дебаты вокруг goto утихли, но короткая экскурсия по современным репозиториям исходного кода, http:y/cc2e.com/1785 таким как SourceForge.net, показывает, что goto все еще жив-здоров и глубоко укоренился на сервере вашей компании. Более того, современные эквиваленты обсуждения goto до сих пор возникают под разными личинами, включая дебаты о множественных возвратах из методов, множественных выходах из цикла, именованных выходах из цикла, обработке ошибок и исключений.

Аргументы против goto

Основной аргумент против goto состоит в том, что код без goto - более качественный. Знаменитое письмо Дейкстры «Go То Statement Considered Harmful» («Обоснование пагубности оператора go to») в мартовском номере «Communications of the АСМ» 1968 г. положило начало дискуссии. Дейкстра отметил, что качество кода

Пример неправильного решения: вычисления jn факториала с помощью рекурсии (Java)

int Factorial( int number ) { if ( number 1 ) { return 1;

else {

return number * Factorial( number - 1 );

He считая медленного выполнения и непредсказуемого использования памяти, рекурсивный вариант функции трудней для понимания, чем итеративный вариант:

Пример правильного решения: использование итераций для вычисления факториала (Java:)

int Factorial( int number ) { int intermediateResult = 1;

for ( int factor = 2; factor <= number; factor++ ) { intermediateResult = intermediateResult * factor;

return intermediateResult;

Из этого примера можно усвоить три урока. Первый: учебники по ВычТеху не оказывают миру услугу своими примерами рекурсии. Второй, и более важный: рекурсия - гораздо более мощный инструмент, чем можно предположить из сбивающих с толку примеров расчета факториала и чисел Фибоначчи. Третий - самый важный: вы должны рассмотреть альтернативные варианты перед использованием рекурсии. Иногда один способ работает лучше, иногда - другой. Но прежде чем выбрать какой-то один, надо рассмотреть оба.



обратно пропорционально количеству goto, использованных программистом. В последующих работах Дейкстра утверждал, что корректность кода, не содержащего goto, доказать легче.

Код с операторами goto трудно форматировать. Для демонстрации логической структуры используются отступы, а goto влияет на логическую структуру. Однако использовать отступы, чтобы показать логику goto и места его перехода, сложно или даже невозможно.

Применение goto препятствует оптимизации, выполняемой компилятором. Некоторые виды оптимизации зависят от порядка выполнения нескольких выражений подряд. Безусловный переход goto усложняет анализ кода и уменьшает возможность оптимизации кода компилятором. Таким образом, даже если применение goto увеличивает эффективность на уровне исходного кода, суммарный эффект из-за невозможности оптимизации может уменьшиться.

Сторонники операторов goto иногда приводят довод, что они делают программу быстрее и проще. Но код, содержащий goto, обычно не самый быстрый и короткий из всех возможных. Изумительная классическая статья Дональда Кнута «Struc-tured Programming with go to Statements» («Структурное программирование и операторы go to») содержит несколько примеров, в которых применение goto приводит к более медленному и объемному коду (Knuth, 1974).

На практике применение операторов goto приводит к нарушению принципа, что нормальный ход алгоритма должен быть строго сверху вниз. Даже если goto при аккуратном использовании не сбивают с толку, как только они появляются, они начинают распространяться по коду, как термиты по разрушающемуся дому. Если разрешен хотя бы один goto, вместе с пользой в код проникает и вред, так что лучше вообще запретить использование этого оператора.

В целом опыт двух десятилетий, прошедших с публикации письма Дейкстры показал всю недальновидность создания кода, перегруженного операторами goto. В своем обзоре литературы Бен Шнейдерман (Ben Shneiderman) сделал вывод, что факты свидетельствуют в пользу Дейкстры и нам лучше обходиться без goto (1980), а многие современные языки, включая Java, даже не содержат такой оператор.

Аргументы в защиту goto

Сторонники goto ратуют за осторожное применение оператора при определенных обстоятельствах, а не за неразборчивое употребление. Большинство аргументов против goo говорит именно о неразборчивом его использовании. Дискуссия о goto вспыхнула, когда Fortran был наиболее популярным языком. Fortran не имел приличных циклов, и в отсутствие хорошего совета по поводу создания цикла с помощью goto программисты написали кучу спагетти-кода. Такой код, несомненно, коррелировал с выпуском низкокачественных программ, но это имело отдаленное отношение к аккуратному использованию goto, позволяющему заполнить пробел в возможностях, предоставляемых современными языками программирования.

Правильно расположенный goto способен помочь избавиться от дублирования кода. Такой код создает проблемы, если две его части модифицируются по-разному Дублированный код увеличивает размер исходного и выполняемого файлов. Отри-



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 [128] 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294



0.0023