Есть несколько причин для использования оператора "goto", о котором я знаю (некоторые уже говорили об этом):
Чисто выход из функции
Часто в функции вы можете распределять ресурсы и должны выходить из нескольких мест. Программисты могут упростить свой код, поместив код очистки ресурса в конец функции, и все «точки выхода» функции перейдут к метке очистки. Таким образом, вам не нужно писать код очистки в каждой «точке выхода» функции.
Выход из вложенных циклов
Если вы находитесь во вложенном цикле и хотите выйти из всех циклов, goto может сделать это намного чище и проще, чем операторы break и if-проверки.
Улучшения на низком уровне производительности
Это действительно только в критически важном коде, но операторы goto выполняются очень быстро и могут дать вам толчок при перемещении по функции. Однако это обоюдоострый меч, потому что компилятор обычно не может оптимизировать код, содержащий gotos.
Обратите внимание, что во всех этих примерах gotos ограничены областью действия одной функции.
goto
наreturn
это просто глупо. Это не «рефакторинг» ничего, это просто «переименование», чтобы люди, выросшие вgoto
подавленной среде (то есть все мы), чувствовали себя лучше при использовании того, что морально равнозначно agoto
. Я предпочитаю видеть цикл, в котором я его использую, и видеть немногоgoto
, который сам по себе является просто инструментом , чем видеть, как кто-то переместил цикл куда-то, не связанное только для того, чтобы избежатьgoto
.break
,continue
,return
в основномgoto
, только в красивой упаковке.do{....}while(0)
должна быть лучшая идея, чем goto, за исключением того факта, что она работает в Java.Все, кто
goto
прямо или косвенно против, цитирует статью Эдсгера Дейкстры « Считается вредной» для обоснования своей позиции. Жаль, что статья Дейкстры практически не имеет отношения к тому, какgoto
в наши дни используются операторы, и, следовательно, то, что говорится в статье, практически не применимо к современной сцене программирования. Вgoto
-Меньше мем обочинах сейчас на религию, вплоть до его писаниях продиктованы высоко, его первосвященники и избегания (или хуже) воспринимаемых еретиков.Давайте поместим статью Дейкстры в контекст, чтобы пролить немного света на эту тему.
Когда Дейкстра написал свою статью, популярными языками того времени были неструктурированные процедурные языки, такие как бейсик, фортран (более ранние диалекты) и различные языки ассемблера. Люди, использующие языки более высокого уровня, довольно часто перепрыгивали всю свою кодовую базу в искаженных, искаженных потоках выполнения, что породило термин «код спагетти». Вы можете увидеть это, перейдя к классической игре Trek, написанной Майком Мэйфилдом, и попытайтесь понять, как все работает. Потратьте несколько минут, чтобы просмотреть это.
ЭТО является «необузданное использование идти на заявление» , что Дейкстра был поругал в своей статье в 1968 г. Этот является средой , он жил в том , что привело его написать эту бумагу. Возможность прыгать в любом месте вашего кода в любое удобное для вас место было тем, что он критиковал и требовал прекратить. Сравнивая это с анемичными силами
goto
Си или других более современных языков просто невозможно.Я уже слышу поднятые крики культистов, когда они сталкиваются с еретиком. «Но, - будут повторять они, - вы можете сделать код, с которым очень трудно читать
goto
на языке Си». О да? Вы также можете сделать код очень сложным для чтения без негоgoto
. Как этот:Не
goto
видно, так что это должно быть легко читать, верно? Или как насчет этого:Нет
goto
там тоже. Поэтому он должен быть читабельным.Какой смысл в этих примерах? Это не языковые функции, которые делают нечитаемый, не поддерживаемый код. Это не синтаксис, который делает это. Это плохие программисты, которые вызывают это. И плохие программисты, как вы можете видеть в этом пункте, могут сделать любую языковую функцию нечитаемой и непригодной для использования. Как
for
петли там. (Вы можете видеть их, верно?)Теперь, чтобы быть справедливым, некоторые языковые конструкции легче злоупотреблять, чем другие. Однако, если вы программист на C, я бы посмотрел гораздо ближе примерно на 50% случаев использования
#define
задолго до того, как начать крестовый походgoto
!Итак, для тех, кто потрудился прочитать это далеко, есть несколько ключевых моментов, на которые следует обратить внимание.
goto
утверждениях была написана для среды программирования, котораяgoto
была гораздо более потенциально опасной, чем в большинстве современных языков, которые не являются ассемблером.goto
из-за этого примерно так же рационально, как сказать: «Я однажды пытался повеселиться, но мне это не понравилось, так что теперь я против».goto
операторов в коде, которые не могут быть адекватно заменены другими конструкциями.godo
» мерзость, где всегда используется ложнаяdo
петляbreak
вместо использования вместоgoto
. Они часто хуже, чем разумное использованиеgoto
.источник
goto
самом деле преимущества (и это вопрос)Повиновение лучшим практикам вслепую не является лучшей практикой. Идея избегать
goto
операторов как основной формы управления потоком состоит в том, чтобы не создавать нечитаемый код спагетти. Если их экономно использовать в нужных местах, иногда они могут быть самым простым и ясным способом выражения идеи. Уолтер Брайт, создатель компилятора Zortech C ++ и языка программирования D, использует их часто, но разумно. Даже сgoto
заявлениями его код все еще отлично читается.Итог:
goto
избегать ради избеганияgoto
бессмысленно. Чего вы действительно хотите избежать, так это создавать нечитаемый код. Если вашgoto
код -laden читабелен, то в этом нет ничего плохого.источник
Так как
goto
делает рассуждение о потоке программы 1 (он же «код спагетти»),goto
обычно используется только для компенсации отсутствующих функций: использованиеgoto
может фактически быть приемлемым, но только если язык не предлагает более структурированный вариант для получения та же цель. Возьмите пример сомнения:Это верно - но только если язык не позволяет структурированную обработку исключений с помощью кода очистки (такого как RAII или
finally
), который выполняет ту же работу лучше (так как он специально создан для этого), или когда есть веская причина, не использовать структурированную обработку исключений (но у вас никогда не будет этого случая, кроме как на очень низком уровне).В большинстве других языков единственным приемлемым использованием
goto
является выход из вложенных циклов. И даже там почти всегда лучше поднять внешний цикл в собственный метод и использоватьreturn
вместо него.Кроме этого,
goto
это признак того, что недостаточно внимания было уделено конкретному коду.1 Современные языки, которые поддерживают,
goto
реализуют некоторые ограничения (например,goto
могут не входить в функции или выходить из них), но проблема в основном остается той же.Между прочим, то же самое, конечно, верно и для других языковых функций, в частности, исключений. И обычно существуют строгие правила использования этих функций только там, где это указано, например, правило не использовать исключения для управления неисключительным потоком программ.
источник
finally
? Таким образом, использование исключений для других вещей, кроме обработки ошибок, хорошо, а использованиеgoto
- плохо? Я думаю, что исключения довольно удачно названы.Ну, есть одна вещь, которая всегда хуже
goto's
; странное использование других операторов потока программ, чтобы избежать перехода:Примеры:
источник
do{}while(false)
Я думаю, что можно считать идиоматическим. Вы не можете не соглашаться: Dgoto after_do_block;
фактически не говоря этого. Иначе ... «цикл», который запускается ровно один раз? Я бы назвал это злоупотреблением контрольными структурами.#define
много, много раз намного хуже, чемgoto
время от времени: DВ операторе C # switch не допускается провал . Таким образом, goto используется для передачи управления определенной метке переключения или метке по умолчанию .
Например:
Изменить: есть одно исключение из правила "без провала". Прорыв разрешен, если в регистре нет кода.
источник
goto case 5:
когда вы в случае 1). Похоже, что ответ Конрада Рудольфа здесь правильный:goto
он компенсирует отсутствующую функцию (и менее ясен, чем реальная функция). Если то, что мы действительно хотим, - это провал, возможно, лучшим вариантом по умолчанию будет не провал, а что-то вродеcontinue
явного запроса.#ifdef TONGUE_IN_CHEEK
В Perl есть функция
goto
, позволяющая вам выполнять хвостовые вызовы бедняков. :-П#endif
Хорошо, так что это не имеет ничего общего с Си
goto
. Более серьезно, я согласен с другими комментариями об использованииgoto
для очистки, или для реализации устройства Даффа , или тому подобное. Все дело в использовании, а не в злоупотреблении.(Один и тот же комментарий может применяться к
longjmp
исключениямcall/cc
и т. П. - они имеют законное применение, но их легко злоупотреблять. Например, выбрасывать исключение просто для того, чтобы избежать глубоко вложенной структуры управления, в совершенно неисключительных обстоятельствах .)источник
За эти годы я написал более нескольких строк на ассемблере. В конечном счете, каждый язык высокого уровня компилируется в gotos. Хорошо, назовите их "ветви" или "прыжки" или как-нибудь еще, но они gotos. Кто-нибудь может написать goto-less ассемблер?
Теперь, конечно, вы можете указать программисту на Fortran, C или BASIC, что запуск бунта с gotos - это рецепт болгарского спагетти. Ответ, однако, не в том, чтобы избежать их, а в том, чтобы использовать их осторожно.
Нож можно использовать для приготовления пищи, освобождения кого-либо или убийства. Обойдемся ли мы без ножей из-за страха перед последним? Точно так же goto: используется небрежно, это мешает, используется тщательно, это помогает.
источник
Посмотрите, когда использовать Goto при программировании на C :
Что я имею в виду? Вы могли бы иметь некоторый код, который выглядит так:
Это нормально, пока вы не поймете, что вам нужно изменить код очистки. Затем вы должны пройти и внести 4 изменения. Теперь вы можете решить, что можете просто инкапсулировать всю очистку в одну функцию; это не плохая идея. Но это означает, что вам нужно быть осторожным с указателями - если вы планируете освободить указатель в своей функции очистки, нет способа установить его так, чтобы он указывал на NULL, если вы не передадите указатель на указатель. Во многих случаях вы не будете использовать этот указатель в любом случае, так что это может быть не основной проблемой. С другой стороны, если вы добавите новый указатель, дескриптор файла или другую вещь, которая нуждается в очистке, то вам придется снова изменить свою функцию очистки; и тогда вам нужно изменить аргументы этой функции.
Используя
goto
, это будетПреимущество здесь в том, что ваш код, следующий за концом, имеет доступ ко всему, что потребуется для выполнения очистки, и вам удалось значительно сократить количество точек изменения. Другое преимущество состоит в том, что вы перешли от нескольких точек выхода для вашей функции к одной; нет никакого шанса, что вы случайно вернетесь из функции без очистки.
Более того, поскольку goto используется только для перехода к одной точке, это не значит, что вы создаете массу спагетти-кода, скачущего вперед и назад в попытке симулировать вызовы функций. Скорее, goto на самом деле помогает писать более структурированный код.
Одним словом,
goto
всегда следует использовать экономно и в крайнем случае - но для этого есть время и место. Вопрос должен быть не в том, «нужно ли вам это использовать», а в том, «лучший ли это выбор».источник
Одной из причин плохого перехода является то, что помимо стиля кодирования вы можете использовать его для создания перекрывающихся , но не вложенных циклов:
Это создало бы причудливую, но, возможно, легальную структуру управления потоком, где возможна последовательность типа (a, b, c, b, a, b, a, b, ...), что делает хакеров компилятора несчастными. Очевидно, есть ряд хитрых приемов оптимизации, которые основаны на том, что такого типа структуры не существует. (Я должен проверить мою копию книги о драконах ...) В результате (при использовании некоторых компиляторов) это может привести к тому, что другие оптимизации не будут выполнены для кода, содержащего
goto
s.Это может быть полезно, если вы знаете, что «о, кстати», случается, убедить компилятор генерировать более быстрый код. Лично я предпочел бы попытаться объяснить компилятору, что возможно, а что нет, прежде чем использовать такой трюк, как goto, но, возможно, я мог бы также попытаться это сделать,
goto
прежде чем взламывать ассемблер.источник
goto
является полезным является то , что она позволяет построить петлю , как это, что потребовало бы кутит логические судороги иначе. Кроме того, я бы сказал, что если оптимизатор не знает, как это переписать, то это хорошо . Подобный цикл должен быть сделан не для производительности или читабельности, а потому, что это именно тот порядок, в котором все должно происходить. В этом случае я бы не хотел, чтобы оптимизатор работал с ним.Я нахожу забавным, что некоторые люди заходят так далеко, что приводят список случаев, когда goto приемлемо, говоря, что любое другое использование недопустимо. Вы действительно думаете, что знаете каждый случай, когда goto - лучший выбор для выражения алгоритма?
Чтобы проиллюстрировать это, я приведу пример, который еще никто здесь не показывал:
Сегодня я писал код для вставки элемента в хеш-таблицу. Хеш-таблица представляет собой кэш предыдущих вычислений, который может быть перезаписан по желанию (влияет на производительность, но не на корректность).
Каждое ведро хеш-таблицы имеет 4 слота, и у меня есть несколько критериев, чтобы решить, какой элемент перезаписать при заполнении ячейки. Прямо сейчас это означает сделать до трех проходов через ковш, как это:
Если бы я не использовал goto, как бы выглядел этот код?
Что-то вроде этого:
Будет выглядеть хуже и хуже, если будет добавлено больше проходов, в то время как версия с goto всегда сохраняет один и тот же уровень отступа и избегает использования ложных операторов if, результат которых подразумевается при выполнении предыдущего цикла.
Так что есть еще один случай, когда goto делает код чище и проще для написания и понимания ... Я уверен, что есть еще много, так что не делайте вид, что знаете все случаи, когда goto полезен, отбрасывая любые хорошие, которые вы не могли не думаю о.
источник
goto
иметь каждую функцию на одном уровне абстракции. То, что он избегает,goto
является бонусом.container::iterator it = slot_p.find(hash_key); if (it != slot_p.end()) it->overwrite(hash_key); else it = slot_p.find_first_empty();
я считаю, что такого рода программирование намного легче читать. Каждая функция в этом случае может быть написана как чистая функция, о которой гораздо проще рассуждать. Функция main теперь объясняет, что делает код, просто по имени функций, а затем, если хотите, вы можете посмотреть на их определения, чтобы узнать, как он это делает.Правило goto, которое мы используем, заключается в том, что goto подходит для перехода вперед к одной точке очистки выхода в функции. В действительно сложных функциях мы ослабляем это правило, чтобы позволить другим прыгать вперед. В обоих случаях мы избегаем глубоко вложенных операторов if, которые часто встречаются при проверке кода ошибки, что способствует удобочитаемости и обслуживанию.
источник
Наиболее вдумчивое и тщательное обсуждение операторов goto, их законного использования и альтернативных конструкций, которые можно использовать вместо «добродетельных утверждений goto», но которыми можно злоупотреблять так же легко, как и заявлениями goto, - это статья Дональда Кнута « Структурное программирование с утверждениями goto » , в декабре 1974 года, «Компьютерные обзоры» (том 6, № 4, с. 261 - 301).
Не удивительно, что некоторые аспекты этой 39-летней статьи устарели: увеличение вычислительной мощности на несколько порядков делает некоторые улучшения производительности Knuth незаметными для задач среднего размера, и с тех пор были изобретены новые конструкции на языке программирования. (Например, блоки try-catch включают в себя конструкцию Цана, хотя они редко используются таким образом.) Но Кнут охватывает все стороны аргумента и должен быть прочитан, прежде чем кто-либо еще раз решит проблему.
источник
В модуле Perl вы иногда хотите создавать подпрограммы или замыкания на лету. Дело в том, что как только вы создали подпрограмму, как вы к ней добираетесь. Вы могли бы просто назвать это, но тогда, если подпрограмма использует
caller()
это, не будет так полезно, как могло бы быть. Вот гдеgoto &subroutine
изменение может быть полезным.Вот быстрый пример:
Вы также можете использовать эту форму
goto
для обеспечения элементарной формы оптимизации хвостового вызова.(В Perl 5 версии 16 это было бы лучше написать как
goto __SUB__;
)Есть модуль, который будет импортировать
tail
модификатор и один, который импортирует,recur
если вам не нравится использовать эту формуgoto
.Большинство других причин
goto
лучше использовать с другими ключевыми словами.Например,
redo
немного кода:Или перейдем к
last
фрагменту кода из нескольких мест:источник
C не имеет многоуровневого / помеченного разрыва, и не все потоки управления могут быть легко смоделированы с помощью примитивов C итерации и принятия решения. gotos имеют большое значение для исправления этих недостатков.
Иногда яснее использовать какую-либо переменную flag для выполнения своего рода псевдо-многоуровневого разрыва, но он не всегда превосходит goto (по крайней мере, goto позволяет легко определить, куда идет управление, в отличие от переменной flag ), а иногда вы просто не хотите платить цену производительности флагов / других искажений, чтобы избежать перехода.
libavcodec - это чувствительный к производительности фрагмент кода. Прямое выражение потока управления, вероятно, является приоритетом, потому что оно будет работать лучше.
источник
Точно так же никто никогда не реализовывал утверждение «COME FROM» ....
источник
Я считаю использование do {} while (false) совершенно отвратительным. Возможно, это может убедить меня, что это необходимо в каком-то странном случае, но никогда, что это чистый разумный код.
Если вы должны сделать какой-то такой цикл, почему бы не сделать явной зависимость от переменной-флага?
источник
/*empty*/
бытьstepfailed = 1
? В любом случае, как это лучше, чемdo{}while(0)
? В обоих случаях вам нужноbreak
из нее (или в своюstepfailed = 1; continue;
). Кажется ненужным для меня1) Наиболее распространенное использование goto, о котором я знаю, - это эмуляция обработки исключений в языках, которые этого не предлагают, а именно в C. (Код, приведенный выше в Nuclear, просто так.) Посмотрите на исходный код Linux, и вы ' увидим, как таким образом использовался базилик гото; согласно короткому опросу, проведенному в 2013 году, в коде Linux было около 100 000 кодов goto: http://blog.regehr.org/archives/894 . Использование Goto даже упоминается в руководстве по стилю кодирования Linux: https://www.kernel.org/doc/Documentation/CodingStyle . Подобно тому, как объектно-ориентированное программирование эмулируется с использованием структур, заполненных указателями функций, goto имеет свое место в программировании на Си. Так кто же прав: Дейкстра или Линус (и все кодировщики ядра Linux)? Это теория против практики в принципе.
Тем не менее, существует обычная ошибка, связанная с отсутствием поддержки на уровне компилятора и проверками общих конструкций / шаблонов: проще использовать их неправильно и вводить ошибки без проверок во время компиляции. Windows и Visual C ++, но в режиме C предлагают обработку исключений через SEH / VEH по этой самой причине: исключения полезны даже вне языков ООП, то есть на процедурном языке. Но компилятор не всегда может сохранить ваш бекон, даже если он предлагает синтаксическую поддержку исключений в языке. Рассмотрим в качестве примера последнего случая известную ошибку Apple SSL «goto fail», которая просто дублировала одно goto с катастрофическими последствиями ( https://www.imperialviolet.org/2014/02/22/applebug.html ):
Вы можете получить точно такую же ошибку, используя исключения, поддерживаемые компилятором, например, в C ++:
Но обоих вариантов ошибки можно избежать, если компилятор анализирует и предупреждает вас о недоступном коде. Например, компиляция с Visual C ++ на уровне предупреждения / W4 обнаруживает ошибку в обоих случаях. Java, например, запрещает недоступный код (где он может его найти!) По довольно веской причине: скорее всего, это ошибка в коде обычного Джо. Пока конструкция goto не допускает целей, которые компилятор не может легко определить, например, gotos по вычисляемым адресам (**), компилятору не сложнее найти недоступный код внутри функции с gotos, чем использовать Dijkstra - одобренный код.
(**) Сноска. Переход к вычисленным номерам строк возможен в некоторых версиях Basic, например, GOTO 10 * x, где x - переменная. Весьма странно, что в Фортране «вычисляемое goto» относится к конструкции, которая эквивалентна выражению switch в C. Стандарт C не допускает вычисляемые goto в языке, а только goto для статически / синтаксически объявленных меток. GNU C, однако, имеет расширение для получения адреса метки (унарный оператор, префикс && оператор), а также позволяет перейти к переменной типа void *. См. Https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html для получения дополнительной информации по этой неясной подтеме. Остальная часть этого поста не связана с этой неясной функцией GNU C.
Стандартные C (то есть не вычисляемые) goto обычно не являются причиной, по которой недоступный код не может быть найден во время компиляции. Обычная причина - логический код, подобный следующему. Дано
Компилятору так же трудно найти недоступный код в любой из следующих трех конструкций:
(Извините за мой стиль кодирования, связанный с фигурными скобками, но я старался сделать примеры максимально компактными.)
Visual C ++ / W4 (даже с / Ox) не может найти недоступный код ни в одном из них, и, как вы, вероятно, знаете, проблема поиска недоступного кода вообще неразрешима. (Если вы мне не верите: https://www.cl.cam.ac.uk/teaching/2006/OptComp/slides/lecture02.pdf )
Как связанная с этим проблема, C goto может использоваться для эмуляции исключений только внутри тела функции. Стандартная библиотека C предлагает пару функций setjmp () и longjmp () для эмуляции нелокальных выходов / исключений, но они имеют ряд серьезных недостатков по сравнению с другими языками. Статья в Википедии http://en.wikipedia.org/wiki/Setjmp.h довольно хорошо объясняет эту последнюю проблему. Эта пара функций также работает в Windows ( http://msdn.microsoft.com/en-us/library/yz2ez4as.aspx ), но вряд ли кто-то использует их там, потому что SEH / VEH лучше. Я думаю, что даже в Unix setjmp и longjmp используются очень редко.
2) Я думаю, что вторым наиболее распространенным использованием goto в C является реализация многоуровневого разрыва или многоуровневого продолжения, что также является довольно неоспоримым вариантом использования. Напомним, что Java не разрешает метку goto, но позволяет разорвать или продолжить метку. Согласно http://www.oracle.com/technetwork/java/simple-142616.html , это на самом деле самый распространенный случай использования gotos в C (говорят, что 90%), но, по моему субъективному опыту, системный код имеет тенденцию чаще использовать gotos для обработки ошибок. Возможно, в научном коде или там, где ОС предлагает обработку исключений (Windows), многоуровневые выходы являются доминирующим вариантом использования. Они не дают никаких подробностей относительно контекста своего опроса.
Отредактировано, чтобы добавить: оказывается, что эти два образца использования найдены в книге C Кернигана и Ричи, около страницы 60 (в зависимости от издания). Также следует отметить, что в обоих случаях используются только прямые переходы. И оказывается, что выпуск MISRA C 2012 (в отличие от выпуска 2004 г.) теперь разрешает goto, если они только передовые.
источник
Некоторые говорят, что нет причин для перехода в C ++. Некоторые говорят, что в 99% случаев есть лучшие альтернативы. Это не рассуждения, а просто иррациональные впечатления. Вот хороший пример, где goto приводит к хорошему коду, что-то вроде расширенного цикла do-while:
Сравните это с свободным кодом:
Я вижу эти различия:
{}
блок (хотяdo {...} while
выглядит более знакомым)loop
переменная, используется в четырех местахloop
loop
не имеет каких - либо данных, он просто контролирует поток исполнения, который является менее понятным , чем просто этикеткиЕсть еще один пример
Теперь давайте избавимся от «злого» гото:
Вы видите, что это тот же тип использования goto, это хорошо структурированный паттерн, и он не продвигается вперед, как многие продвигают, как единственный рекомендуемый способ. Конечно, вы хотите избежать «умного» кода, подобного этому:
Дело в том, что goto можно легко использовать неправильно, но само goto не виновато. Обратите внимание, что метка имеет область действия функции в C ++, поэтому она не загрязняет глобальную область видимости, как в чистой сборке, в которой перекрывающиеся циклы имеют свое место и очень распространены - как в следующем коде для 8051, где 7-сегментный дисплей подключен к P1. Программа зацикливает молниеносный сегмент вокруг:
Есть еще одно преимущество: goto может служить именованными циклами, условиями и другими потоками:
Или вы можете использовать эквивалентный переход с отступом, поэтому вам не нужно комментировать, если вы правильно выберете название метки:
источник
В Perl использование метки для «перехода» из цикла - с использованием «последней» инструкции, которая похожа на break.
Это позволяет лучше контролировать вложенные циклы.
Также поддерживается традиционная метка goto , но я не уверен, что существует слишком много случаев, когда это единственный способ достичь того, чего вы хотите - подпрограмм и циклов должно быть достаточно для большинства случаев.
источник
goto &subroutine
. Который запускает подпрограмму с текущим @_, заменяя текущую подпрограмму в стеке.Проблема с «goto» и наиболее важным аргументом движения «goto -less Программирование» заключается в том, что если вы используете его слишком часто, ваш код, хотя он может вести себя правильно, становится нечитаемым, не поддерживаемым, не читаемым и т. Д. В 99,99% случаи "goto" приводят к коду спагетти. Лично я не могу придумать какой-либо веской причины, по которой я бы использовал «goto».
источник
goto
). Использование @ cschol аналогично: хотя, возможно, сейчас он не разрабатывает язык, он (а) в основном оценивает усилия дизайнера.goto
за исключением случаев, когда оно приводит к появлению переменных, может быть дешевле, чем пытаться поддерживать все виды управляющих структур, которые могут кому-то понадобиться. Написание кода с использованиемgoto
может быть не таким приятным, как использование какой-либо другой структуры, но возможность написания такого кодаgoto
поможет избежать «дыр в выразительности» - конструкций, для которых язык не способен писать эффективный код.goto
на сайте обзора кода, устранение этогоgoto
значительно упрощает логику кода.Конечно, GOTO можно использовать, но есть еще одна важная вещь, чем стиль кода, или если код является или не читаемым, что вы должны иметь в виду при его использовании: код внутри может быть не таким надежным, как вы думаю .
Например, посмотрите на следующие два фрагмента кода:
Эквивалентный код с GOTO
Первое, что мы думаем, это то, что результатом обоих битов кода будет «Значение A: 0» (конечно, мы предполагаем выполнение без параллелизма)
Это не правильно: в первом примере A всегда будет 0, но во втором примере (с оператором GOTO) A может не быть 0. Почему?
Причина в том, что из другой точки программы я могу вставить
GOTO FINAL
без контроля значения А.Этот пример очень очевиден, но по мере того, как программы усложняются, становится все труднее видеть такие вещи.
Соответствующий материал можно найти в известной статье г-на Дейкстры «Дело против заявления GO TO»
источник
Я использую goto в следующем случае: когда необходимо вернуться из функций в разных местах, а перед возвращением необходимо выполнить некоторую деинициализацию:
не-goto версия:
Перейти к версии:
Вторая версия облегчает задачу, когда вам нужно что-то изменить в операторах освобождения (каждый из которых используется один раз в коде), и уменьшает вероятность пропустить любой из них при добавлении новой ветви. Перемещение их в функцию здесь не поможет, потому что освобождение может быть сделано на разных «уровнях».
источник
finally
блоки в C #finally
). В качестве альтернативы используйтеgoto
s, но для общей точки выхода, которая всегда выполняет всю очистку. Но каждый метод очистки может обрабатывать нулевое или уже очищенное значение или защищен условным тестом, поэтому пропускается, когда не подходит.goto
s, которые все идут к одной и той же точке выхода, которая имеет ту же логику (которая требует, как вы говорите, дополнительного if для ресурса). Но не берите в голову, что при использованииC
вы правы - независимо от того, по какой причине код написан на C, это почти наверняка компромисс, который благоприятствует наиболее «прямому» коду. (Мое предложение ручки сложных ситуаций , в которых могут быть или не были выделены любой данный ресурс Но да, излишеством в этом случае.)Эдсгер Дейкстра (Edsger Dijkstra), ученый-компьютерщик, внесший значительный вклад в этой области, также был известен своей критикой использования GoTo. Есть небольшая статья о его аргументе в Википедии .
источник
Время от времени он пригодится для посимвольной обработки строк.
Представьте себе что-то вроде этого printf-esque:
Вы можете выполнить рефакторинг
goto handle_literal
для вызова функции, но если он изменяет несколько различных локальных переменных, вам придется передавать ссылки на каждую из них, если только ваш язык не поддерживает изменяемые замыкания. Вам все равно придется использоватьcontinue
оператор (который, возможно, является формой goto) после вызова, чтобы получить ту же семантику, если ваша логика заставляет другой случай не работать.Я также разумно использовал gotos в лексерах, как правило, для подобных случаев. Вы не нуждаетесь в них большую часть времени, но их приятно иметь в тех странных случаях.
источник