Я знаю 2 случая когда goto упрощает код:
1) В функции несколько return и перед каждым нужно освободить память и закрыть дескрипторы. Чтобы не дублировать код, вместо return'ов ставим goto на конец функции и после метки втыкаем весь завершающий код.
2) Выход из нескольких вложенных циклов, когда мы уже всё посчитали, всё понятно но корректно завершить все эти циклы сильный гемор - goto как это не странно упростит код.
Первый случай встречается достаточно часто, второй наоборот, не всегда, но в большинстве случаев удается избежать (честно говоря, помню что такое делал только раз).
Возможно, первое решается использованием using (C#) или RAII.
Второе можно решить вынесением цикла со вложенным циклом в отдельный метод.
если ты серьезно, то goto - это резкий переход к другому коду вообще. А метод это как вызов подпрограммы с прерыванием основной (если что не правильно написал - тыкните носом, но пруфы бы)
Во втором случае можно все циклы засунуть в функцию и использовать return. По факту те же яйца только в профиль, но return как то роднее)
Первый случай напоминает слишком большую функцию, которую можно и нужно разбить на несколько (в том числе, освобождение памяти и закрытие дескрипторов). Второй решается оборачиванием вложенных циклов в функцию, из которой можно вывалиться return'ом.
я бы подумал, что 1 - все фрии и прочее должно делаться неявно в соответствующих деструкторах, но с динамической аллокацией у меня опыта мало, да и от языка зависит.
2. иной раз действительно хочется написать один goto вместо if'ов с брейками на каждый уровень, но привычка говорит использовать строго второй вариант
1) Деструкторы не всегда доступны, например в Сях.
2) У вас скажем есть функция, у неё есть локальные вещи которые не хочется вытаскивать наружу даже на уровень класса, просто чтобы не засирать.
3) Иногда, вместо того чтобы просто дёрнуть функцию приходится сначала инстанцировать объект, затем дергать из него функцию затем этот объект уничтожать (ну или он грохнется сам, если на стеке) и всё только для того чтобы воспользоваться "преимуществом" деструктора.
Но вообще нет плохих или хороших методов, когда гонишь код массово пользуешься всеми известными тебе способами, просто в каждом конкретном случае решаешь что тебе в данный конкретный момент "дешевле". Иногда это зависит даже просто от настроения.
А можно пояснить за 2ой пример? Как иначе выходить из всех циклов? Исключением? Или может тут будет аргумент - "Не делайте циклов в цикле"?)
к слову, некоторые языки имеют конструкцию break(n последних циклов). К сожалению плюсы не среди них
Выделить в отдельный метод и сделать return, когда все посчитано.
Но в любом случае goto запрещают не потому что это вселенское зло, а потому что в неумелых руках оно делает спагетти из любого кода. Насчет аккуратного применения в некоторых случаях ничего не имею против.
1) Можно обернуть всю функцию "А" в функцию "В", которая после вызова "А" выполняет общие инструкции после(перед) вызовом "А".
2) Вначале заведите переменную bBreak, и чекайте её (до)после каждой итерации вложенного цикла. В ситуации когда надо выйти, то устанавливаем её в истина. или в цикле проверка этой переменной для выполнения Break. Да, в каждом вложенном цикле будет это условие, но кто вообще сказал, что узор не должен повторяться?
Выносите цикл со вложенным циклом в отдельный метод. Если в итоге у вас получается 100500 отдельных методов, то очевидно что проблема несколько серьёзнее, чем использование goto.
Вариант не использовать циклов вообще подойдет? Он, конечно же, не единственный.
Но, если тебе нужно goto и это не ассемблер, ты что-то делаешь не так.
Но ссылку на репу с кодом авторства Линуса ты так и не привел. Почему?
Впрочем, я нагуглил занимательную дискуссию:
http://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-...
И да, судя по всему Линус тоже пишет говнокод.
А для обработки ошибок попробуй try ... catch использовать. Ходят слухи, что его специально для этих целей придумали.
Во втором случае - может быть, но я обычно делаю несколько более замудренно. Снаруже цикла объявляю булевскую переменную isComplete = false, когда все посчитали - ставлю ее в true, и на каждом цикле ее проверяю. Если true - то break. Наверное, использовать goto там логичнее - но эстетически это примерно как завершать любой разговор словами "пошел на хуй".
А зачем нужно несколько return'ов? В начале функции создаешь переменную toReturn нужного типа, в конце - ставишь return toReturn, а в самой функции - присваиваешь ей нужное значение. Все. Больше одного return'а в функции - прежде всего, лишняя возможность самому запутаться.
Еще можно использовать goto в некоторых языках, где нет оператора switch. Как-то так:
switch(a) {
case 1:
print("1");
case 2:
print("12");
break;
default:
print("none");
}
_case_1:
if (a != 1) goto _case_2;
print("1");
_case_2:
if (a != 2) goto _case_default;
print("12");
goto _switch_end;
_case_default:
print("none");
_switch_end:
Можно, но лучше не стоит:
if (a != 1)
print("1");
else if (a != 2)
print("12");
else
print("none");
...в воображаемом языке, где не реализован switch/case.
Еще можно использовать goto в некоторых языках, где нет оператора switch. Как-то так:
IT-юмор
5.6K постов52.5K подписчика
Правила сообщества
Не публикуем посты:
1) с большим количеством мата
2) с просьбами о помощи
3) не относящиеся к IT-юмору