Стоит ли когда -нибудь использование GOTO?
-
16-10-2019 - |
Вопрос
goto
почти повсеместно обескуражен. Стоит ли использовать это утверждение?
Решение
Это обсуждалось несколько раз на переполнении стека, и Крис Гиллум суммировал возможное использование goto
:
Чисто выходить из функции
Часто в функции вы можете выделить ресурсы и вам нужно выйти в нескольких местах. Программисты могут упростить свой код, поместив код очистки ресурсов в конце функции, все «точки выхода» функции заставят этикетку очистки. Таким образом, вам не нужно писать код очистки в каждой «точке выхода» функции.
Выход из вложенных петлей
Если вы находитесь в вложенной петле и вам нужно вырваться из все Петли, готе, может сделать это намного чище и проще, чем операторы разрыва, и если проверить.
Улучшения производительности низкого уровня
Это действительно только в перф-критическом коде, но операторы GOTO очень быстро выполняются и могут дать вам повышение при прохождении функции. Однако это обоюдоострый меч, потому что компилятор обычно не может оптимизировать код, который содержит GotoS.
Я бы сказал, как многие другие утверждают, что во всех этих случаях использование goto
используется в качестве средства, чтобы выйти из угла, в котором можно кодировать себя, и, как правило, является симптомом кода, который может быть рефактор.
Другие советы
Конструкции управления более высокого уровня, как правило, соответствуют понятиям в проблемной области. If/else - это решение, основанное на каком -то состоянии. В цикле говорится, чтобы выполнить какое -то действие неоднократно. Даже в заявлении перерыва говорится: «Мы делали это неоднократно, но теперь нам нужно остановиться».
С другой стороны, утверждение GOTO, как правило, соответствует концепции в программе работы, а не в проблемном домене. Он говорит, чтобы продолжить исполнение в указанной точке в программе. Анкет Кто -то читает код вывод Что это означает в отношении проблемной области.
Конечно, все конструкции более высокого уровня могут быть определены с точки зрения GOTO и простых условных ветвей. Это не значит, что они просто замаскированы. Думать о них как ограниченный Gotos - и это ограничения, которые делают их полезными. Заявление о перерыве осуществляется как прыжок к концу петли, но лучше думать о том, чтобы работать на цикле в целом.
При прочих равных, код, структура которой отражает структуру проблемы с доменом, имеет тенденцию читать и поддерживать.
Нет случаев, когда заявление о Goto абсолютно требуется (есть теорема Для этого), но есть случаи, когда это может быть наименее плохое решение. Эти случаи варьируются от языка к языку, в зависимости от того, какие конструкции более высокого уровня поддерживает язык.
Например, в C, я считаю, что есть три основных сценария, в которых подходит Goto.
- Вырвавшись из вложенной петли. Это было бы ненужно, если бы на языке было отмеченное заявление о перерыве.
- Выполнение от участка кода (как правило, корпус функции) в случае ошибки или другого неожиданного события. Это было бы ненужно, если бы у языка были исключения.
- Внедрение явного конечного состояния машины. В этом случае (и, я думаю, только в этом случае) goto непосредственно соответствует концепции в проблемной домене, переходя из одного состояния в указанное другое состояние, где текущее состояние представлено, с помощью которого в настоящее время выполняется блок кода Анкет
С другой стороны, явная машина конечного состояния также может быть реализована с оператором переключателя внутри цикла. Это имеет преимущество, которое каждое состояние начинается в одном и том же месте в коде, что может быть полезно для отладки, например.
Основное использование GOTO на достаточно современном языке (тот, который поддерживает, если/else и петли) состоит в том, чтобы имитировать конструкцию потока управления, которая отсутствует на языке.
Конечно, это зависит от языка программирования. Главная причина goto
Был спорным из -за его вредных последствий, которые возникают, когда компилятор позволяет вам использовать его слишком либерально. Проблемы могут возникнуть, например, если это позволяет вам использовать goto
Таким образом, теперь вы можете получить доступ к неонициализированной переменной или, что еще хуже, перейти к другому методу и возиться со стеком вызовов. Компилятор должен быть обязанностью запретить бессмысленному потоку управления.
Java попыталась «решить» эту проблему, не допустившись goto
полностью. Тем не менее, Java позволяет вам использовать return
внутри а finally
блокируйте и, таким образом, вызывает исключение непреднамеренно поглощено. Та же проблема все еще существует: компилятор не выполняет свою работу. Удаление goto
Из языка это не исправило.
В C#, goto
так же безопасно, как break
, continue
, try/catch/finally
а также return
. Анкет Это не позволяет вам использовать неонициализированные переменные, не позволяет вам выпрыгнуть из блока, наконец, и т. Д. Компилятор будет жаловаться. Это потому, что решает настоящий Проблема, которая, как я сказал, бессмысленный поток контроля. goto
Магически не отменяет анализа определенного согласия и другие разумные проверки компилятора.
Да. Когда ваши петли вложены в несколько уровней глубоко, goto
это Только способ элегантного выхода из внутренней петли. Другой вариант - установить флаг и вырваться из каждой петли, если этот флаг удовлетворяет условию. Это действительно уродливо и склонен к ошибкам. В этих случаях, goto
просто лучше.
Конечно, Java помечен break
Заявление делает то же самое, но, не позволяя вам прыгать в произвольную точку в коде, которая аккуратно решает проблему, не позволяя сделать вещи, которые производят goto
зло.
Большая часть разочарования приходит со стороны своего рода «религии», которая была создана Богом Бога Джикстра, которая была убедительной в начале 60 -х годов о своей неизбирательной власти:
- Прыгайте куда угодно в любой блок кода
- функция не выполнена с начала
- петли не выполнены с самого начала
- пропущенная инициализация переменной
- Отпрыгните от любого блока кода без какой -либо возможной очистки.
Это больше не имеет ничего общего с goto
Заявление современных языков, существование которого связано с тем, чтобы поддержать создание кодовых структур, кроме полученных языков.
В частности, первый основной момент выше разрешено, а второй очищается (если вы goto
Из блока стек неразреженный должным образом, и все правильные деструкторы) называются)
Вы можете обратиться этот ответ Чтобы иметь представление о том, как даже код, не использующий GOTO, может быть нечитаемым. Проблема не само по себе, а плохое использование.
Я могу написать всю программу без использования if
, просто for
Анкет Конечно, это не будет хорошо читаемо, выглядит неуклюже и излишне сложным.
Но проблема не for
. Анкет Это я.
Вещи как break
, continue
, throw
, bool needed=true; while(needed) {...}
, и т. д. отмечают больше, чем маскарад goto
Чтобы сбежать от ссорец диджикстрарных фанатиков, через 40 лет после изобретения современных лагуж - все еще хотят их заключенных. Они забыли, о чем говорил Джикстра, они помнят только название его записки (Гото считал вредным, и это было даже не его название ONW: это было изменено редактором) и обвинить и избить, избить и обвинять каждый контракт, имея эти 4 буква размещена в последовательности.
Это 2011: пришло время понять, что goto
есть отметить, чтобы справиться с GOTO
Заявление Джикстра был убедительным.
Странная гостика здесь или там, если он локален для функции, редко существенно наносит ущерб читабельности. Это часто приносит пользу, привлекая внимание к тому факту, что в этом коде есть что -то необычное, что требует использования несколько необычной структуры управления.
Если (локальные) GotoS значительно наносят ущерб читабельности, то обычно это признак того, что функция, содержащая Goto, стала слишком сложной.
Последнее, что я положил в кусок C кода C, состояла в том, чтобы построить пару переплетенных петлей. Это не вписывается в нормальное определение «приемлемого» использования GOTO, но в результате функция оказалась значительно меньше и яснее. Чтобы избежать того, чтобы GOTO потребовало бы особенно грязного нарушения сухой.
Я думаю, что вся эта проблема была случаем лая неверного дерева.
Как таковой не кажется мне проблематичным, а скорее это очень часто симптом реального греха: кода спагетти.
Если GOTO вызывает серьезную пересечение линий управления потоком, то это плохо, точка. Если он не пересекает линии управления потоком, это безвредно. В серой зоне, между ними, у нас есть такие вещи, как спасение петли, есть все еще некоторые языки, которые не добавляли конструкции, которые охватывают все законные серые дела.
Единственный случай, когда я обнаружил, что на самом деле использую его за многие годы, - это случай цикла, где точка решения находится в середине цикла. Вы остаетесь с дублированным кодом, флагом или гото. Я нахожу решение GOTO лучшим из трех. Здесь нет пересечения линий управления потоком, это безвредно.
Да, GOTO может быть использован, чтобы принести пользу опыту разработчика:http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/
Однако, как и в случае с любым мощным инструментом (указатели, множественное наследство и т. Д.), С помощью его следует дисциплинировать. Пример, приведенный в ссылке, использует PHP, который ограничивает использование конструкции GOTO в той же функции/методе и отключает возможность прыгать в новый блок управления (например, цикл, оператор переключения и т. Д.)
Зависит от языка. Например, он все еще широко используется в программировании COBOL. Я также работал над устройством Barionet 50, чей язык программирования прошивки является ранним базовым диалектом, который, конечно, требует от вас использовать GOTO.
Я бы сказал нет. Если вы найдете необходимость использования GOTO, держу пари, что есть необходимость в перепроектировании кода.
goto
может быть полезен при переносе кода устаревшего ассемблера в C. В первую очередь преобразование обучения в C-инструктике в C, используя goto
в качестве замены для ассемблера branch
Инструкция может включить очень быструю портирование.
Я бы спорил нет. Их всегда следует заменять инструментом, более конкретным для проблемы, которую GOTO используется для решения (если только он недоступен на вашем языке). Например, операторы и исключения разрывы решают ранее выдвинутые проблемы с выключением цикла и обработку ошибок.