Примеры хороших gotos на C или C++

В этой теме мы рассмотрим примеры правильного использования goto в C или C++. Он вдохновлен ответ, за который люди проголосовали, потому что думали, что я шучу.

Резюме (ярлык изменен с оригинала, чтобы прояснить намерения):

infinite_loop:

    // code goes here

goto infinite_loop;

Почему лучше альтернатив:

  • Это специфично. goto - это языковая конструкция, которая вызывает безусловная ветвь. Альтернативы зависят от использования структур поддерживающие условные ветви, с вырожденным всегда верным условие.
  • Этикетка документирует намерение без лишних комментариев.
  • Читателю не нужно сканировать промежуточный код для ранних break (хотя все еще возможно беспринципный хакер симулировать continue с ранним goto).

Правила:

  • Представьте, что готофобы не выиграть. Понятно, что выше нельзя использовать в реальном коде, потому что это противоречит устоявшейся идиоме.
  • Предположим, что все мы слышали о 'Гото считается вредным' и знай этот goto можно использовать для записи код спагетти.
  • Если вы не согласны с примером, критиковать это по техническим причинам один ('Потому что людям не нравится goto 'не является технической причиной).

Посмотрим, сможем ли мы говорить об этом, как взрослые.

Редактировать

Этот вопрос кажется законченным. Это дало несколько качественных ответов. Спасибо всем, особенно те, кто серьезно относился к моему примеру с петлей. Большинство скептиков были обеспокоены из-за отсутствия блочного прицела. Как отметил @quinmars в комментарии, вы всегда можете поставить скобки вокруг тело петли. Замечу попутно, что for(;;) и while(true) не дают вам брекетов. бесплатно (и их пропуск может вызвать досадные ошибки). В любом случае, я больше не буду тратить впустую Я могу жить с безобидными и идиоматическими for(;;) и while(true) (с тем же успехом, если я хочу сохранить свою работу).

Принимая во внимание другие отзывы, я вижу, что многие люди рассматривают goto как то, что вы всегда придется по другому переписать. Конечно, вы можете избежать появления goto, введя цикл, дополнительный флаг, стек вложенных if или что-то еще, но почему бы не подумать, является ли goto возможно лучший инструмент для работы? Другими словами, на сколько уродства готовы вынести люди, чтобы избежать использования встроенной языковой функции по прямому назначению? Я считаю, что даже установка флага - слишком высокая цена. Мне нравится, когда мои переменные представляют вещи в области проблемы или решения. «Исключительно для того, чтобы избежать goto», это не сокращает.

Я приму первый ответ, который дал шаблон C для перехода к блоку очистки. ИМО, это самый веский аргумент в пользу goto из всех опубликованных ответов, конечно если вы измеряете это искажениями, через которые должен пройти ненавистник, чтобы избежать этого.

Я не понимаю, почему готофобы просто не предписывают "#define goto report_to_your_supervisor_for_re_education_through_labour" в верхней части включаемого файла проекта. Если это всегда неправильно, сделайте это невозможным. В остальном иногда бывает правильно ...

Steve Jessop 30.10.2008 04:36

"нельзя использовать в реальном коде"? Я использую его в «реальном» коде каждый раз, когда это лучший инструмент для работы. «Установленная идиома» - хороший эвфемизм для «слепого догматизма».

Dan Moulding 18.08.2010 19:58

Я согласен с тем, что «goto» может быть полезным (ниже приведены отличные примеры), но я не согласен с вашим конкретным примером. Строка с надписью «goto infinite_loop» звучит так, как будто она означает «перейти к той части кода, где мы собираемся начать цикл навсегда», как в «initialize (); set_things_up (); goto infinite_loop;» когда на самом деле вы имеете в виду «начать следующую итерацию цикла, в котором мы уже находимся», что совершенно другое. Если вы пытаетесь создать цикл, а в вашем языке есть конструкции, разработанные специально для цикла, используйте их для ясности. while (true) {foo ()} довольно недвусмысленно.

Josh 21.12.2010 22:00

Одним из основных недостатков вашего примера является то, что неясно, какое место охтер в коде может решить перейти к этой метке. «Обычный» бесконечный цикл (for (;;)) не имеет неожиданных точек входа.

jalf 05.01.2011 22:56

@ Дьёрдь: да, но это не отправная точка.

jalf 05.03.2011 13:36

См. Статью Кнута «Структурированное программирование с использованием операторов перехода».

Jim Balter 06.03.2011 01:34
stackoverflow.com/questions/7334952/…
Lightness Races in Orbit 18.01.2013 00:44

Другой способ, если кто-то хочет убить вас из-за goto, попробуйте использовать do{}while(0);, как в этой конструкции do{ if ( 1 > 0 ){ break;} } while(0);

Undefined Behavior 17.12.2014 16:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
79
8
161 191
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Вот пример хорошего goto:

// No Code

эээ, нет gotos? (неудачная попытка смешного: d)

moogs 29.10.2008 07:18

Это не очень полезно

Joseph 20.11.2013 15:27

Я подумал, что это было забавно. Отличная работа. +1

Fantastic Mr Fox 23.10.2014 04:13

@FlySwat FYI: Нашел это в очереди на проверку низкого качества. Рассмотрите возможность редактирования.

Paul 26.10.2014 10:29

Я ничего не имею против gotos в целом, но я могу придумать несколько причин, по которым вы не захотите использовать их для цикла, как вы упомянули:

  • Он не ограничивает область видимости, поэтому любые временные переменные, которые вы используете внутри, не будут освобождены позже.
  • Это не ограничивает возможности, поэтому может привести к ошибкам.
  • Это не ограничивает область видимости, поэтому вы не можете повторно использовать те же имена переменных позже в будущем коде в той же области.
  • Это не ограничивает область видимости, поэтому у вас есть возможность пропустить объявление переменной.
  • Люди не привыкли к этому, и это затруднит чтение вашего кода.
  • Вложенные циклы этого типа могут привести к спагетти-коду, нормальные циклы не приведут к спагетти-коду.

это inf_loop: {/ * тело цикла * /} goto inf_loop; лучше? :)

quinmars 29.10.2008 12:39

Пункты 1-4 являются сомнительными для этого примера даже без фигурных скобок. 1 Это бесконечный цикл. 2 Слишком расплывчато, чтобы адресовать. 3 Пытаться скрыть переменную с тем же именем во включающей области видимости - плохая практика. 4. Обратный переход не может пропустить объявление.

fizzer 30.10.2008 10:44

1-4, как и во всех бесконечных циклах, в середине обычно есть какое-то условие разрыва. Значит они применимы. Re a bakward goto не может пропустить объявление ... не все goto являются обратными ...

Brian R. Bondy 31.10.2008 02:36

Вот мой нелепый пример (от Stevens APITUE) для системных вызовов Unix, которые могут быть прерваны сигналом.

restart:
    if (system_call() == -1) {
        if (errno == EINTR) goto restart;

        // handle real errors
    }

Альтернатива - вырожденный цикл. Эта версия читается как английская «если системный вызов был прерван сигналом, перезапустите его».

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

Ilya 29.10.2008 15:38
while(1){if (system_call() == -1){if (errno == EINTR)continue;//handle real errors}}
Amarghosh 28.05.2010 15:29

@Amarghosh, continue - это просто goto в маске.

jball 03.06.2010 20:31

@jball и более безопасен / удобен (без спагетти-кода), чем goto

Amarghosh 04.06.2010 07:50

@jball ... хм ... ради аргумента, ага; вы можете сделать хорошо читаемый код с помощью goto и спагетти-кода с помощью continue .. В конечном итоге это зависит от человека, который пишет код. Дело в том, что с goto легче заблудиться, чем с continue. И новички обычно используют первый молоток для решения каждой проблемы.

Amarghosh 04.06.2010 08:06

@Amarghosh. Ваш «улучшенный» код даже не эквивалентен оригиналу - в случае успеха он повторяется бесконечно.

fizzer 04.06.2010 16:05

@fizzer oopsie ... ему понадобится два else break (по одному на каждое if), чтобы сделать его эквивалентным ... что я могу сказать ... goto или нет, ваш код настолько хорош, насколько хорош вы :(

Amarghosh 04.06.2010 16:15

@Amarghosh не нужно ни goto, ни else. while (system_call () == -1) if (errno == EINTR) continue; / * обрабатываем реальные ошибки * / break; }

Muhammad Annaqeeb 11.02.2014 08:41

Для этого уже существует макрос TEMP_FAILURE_RETRY (определенный в unistd.h). Реализовано без использования goto: while (__result == -1L && errno == EINTR);.

patryk.beza 16.11.2014 04:04

Если устройству Даффа не требуется goto, то и вам не нужно! ;)

void dsend(int count) {
    int n;
    if (!count) return;
    n = (count + 7) / 8;
    switch (count % 8) {
      case 0: do { puts("case 0");
      case 7:      puts("case 7");
      case 6:      puts("case 6");
      case 5:      puts("case 5");
      case 4:      puts("case 4");
      case 3:      puts("case 3");
      case 2:      puts("case 2");
      case 1:      puts("case 1");
                 } while (--n > 0);
    }
}

код выше из Википедии Вход.

Да ладно, ребята, если вы собираетесь проголосовать против, короткий комментарий о том, почему было бы здорово. :)

Mitch Wheat 29.10.2008 07:46

Это пример логической ошибки, известной также как «обращение к авторитету». Проверьте это в Википедии.

Marcus Griep 29.10.2008 07:51

юмор здесь часто недооценивают ...

Steven A. Lowe 29.10.2008 08:10

Я бы не стал нанимать программиста без чувства юмора.

Mitch Wheat 29.10.2008 08:19

устройство даффа делает пиво?

Steven A. Lowe 30.10.2008 01:07

это может сделать 8 за раз ;-)

Jasper Bekkers 31.10.2008 21:54

Однако не вставляйте это устройство в свой код - на современных машинах оно обычно медленнее, чем memcpy ()

Billy ONeal 11.08.2009 06:46

Митч Уит: наверное, потому, что кто-то отнесся к этому серьезно.

Mechanical snail 12.07.2011 04:48

Устройство Даффа является доказательством того, что goto не вреден: он не использует goto и, тем не менее, настолько похож на спагетти, который человечество редко видит. И если это единственный способ предотвратить переход, я бы предпочел последний. Итак, +0,5 за упоминание устройства Даффа, но -1,1 за его использование в качестве аргумента против goto.

glglgl 20.11.2013 16:05

@glglgl: инструкция switch - это версия C инструкции HP Basic GOTO I OF xx,yy,zz. Перед целями стоит слово case, но они ограничены по объему, но switch в значительной степени является структурой, основанной на goto, о чем свидетельствуют ее правила обхода.

supercat 13.08.2014 21:45
Ответ принят как подходящий

Вот одна уловка, которую я слышал от людей. Хотя я никогда не видел его в дикой природе. И это применимо только к C, потому что в C++ есть RAII, чтобы сделать это более идиоматично.

void foo()
{
    if (!doA())
        goto exit;
    if (!doB())
        goto cleanupA;
    if (!doC())
        goto cleanupB;

    /* everything has succeeded */
    return;

cleanupB:
    undoB();
cleanupA:
    undoA();
exit:
    return;
}

Что в этом плохого? (кроме того факта, что комментарии не понимают символы новой строки) void foo () {if (doA ()) {if (doB ()) {if (doC ()) {/ * все прошло успешно * / return; } undoB (); } undoA (); } возвращаться; }

Artelius 29.10.2008 07:21

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

Adam Rosenfield 29.10.2008 07:42

Вы можете увидеть много такого кода в большинстве низкоуровневых вещей Unix (например, в ядре Linux). В C это лучшая идиома для восстановления ошибок ИМХО.

David Cournapeau 29.10.2008 10:25

Как упоминал Курнап, ядро ​​Linux использует этот стиль все время.

CesarB 29.10.2008 14:00

Не только ядро ​​Linux, посмотрите образцы драйверов Windows от Microsoft, и вы найдете тот же шаблон. В общем, это способ обработки исключений на языке C, и он очень полезен :). Я обычно предпочитаю только 1 этикетку, а в некоторых случаях 2, 3 можно избежать в 99% случаев.

Ilya 29.10.2008 15:37

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

Tim Ring 31.10.2008 12:03

У меня также были проблемы с использованием нескольких возвратов (также полезно в некоторых ситуациях для предотвращения бесконечных уровней отступов и неразборчивых извилистых путей кода).

Tim Ring 31.10.2008 12:06

Почему это лучше, чем просто вызвать undoB () напрямую?

Bob 09.11.2011 14:56

@Bob Старая ветка, которую я знаю, но это потому, что тогда вам нужно было бы сделать undoB(); undoA(); /*goto exit; or return;*/, а если бы у вас был doD(), вам пришлось бы undoC(), а также все элементы, отмененные в неудачном doC().

Joe 04.06.2013 21:34

Именно так goto работает в bat-файле MS-DOS.

The Coordinator 09.01.2014 21:37

Я согласен с Грегом, C++ имеет RAII, поэтому вам никогда не понадобится такой код, но для кода C я бы предпочел код @Artelius без goto.

Muhammad Annaqeeb 11.02.2014 08:44

Одно хорошее место для использования goto - это процедура, которая может прерваться в нескольких точках, каждая из которых требует различных уровней очистки. Gotophobes всегда может заменить gotos структурированным кодом и серией тестов, но я думаю, что это более просто, потому что он устраняет чрезмерные отступы:

if (!openDataFile())
  goto quit;

if (!getDataFromFile())
  goto closeFileAndQuit;

if (!allocateSomeResources)
  goto freeResourcesAndQuit;

// Do more work here....

freeResourcesAndQuit:
   // free resources
closeFileAndQuit:
   // close file
quit:
   // quit!

Я бы заменил это набором функций: freeResourcesCloseFileQuit, closeFileQuit и quit.

RCIX 06.12.2009 11:43

Если вы создали эти 3 дополнительные функции, вам нужно будет передать указатели / дескрипторы ресурсов и файлов, которые нужно освободить / закрыть. Вы, вероятно, заставили бы freeResourcesCloseFileQuit () вызвать closeFileQuit (), который, в свою очередь, вызвал бы quit (). Теперь у вас есть 4 тесно связанных функции, которые нужно поддерживать, и 3 из них, вероятно, будут вызываться не более одного раза: из единственной функции, описанной выше. Если вы настаиваете на том, чтобы избегать goto, IMO, вложенные блоки if () имеют меньше накладных расходов и их легче читать и поддерживать. Что вы получаете с 3 дополнительными функциями?

Adam Liss 07.12.2009 02:59

Меня беспокоит то, что вы теряете область видимости блока; любые локальные переменные, объявленные между gotos, остаются в силе, если цикл когда-либо прерывается. (Возможно, вы предполагаете, что цикл выполняется вечно; однако я не думаю, что это то, что задавал исходный автор вопроса.)

Проблема области видимости больше связана с C++, поскольку некоторые объекты могут зависеть от их dtor, вызываемого в соответствующее время.

Для меня лучшая причина использовать goto - это во время многоэтапного процесса инициализации, когда жизненно важно, чтобы все inits отключались, если один из них выходит из строя, а-ля:

if (!foo_init())
  goto bye;

if (!bar_init())
  goto foo_bye;

if (!xyzzy_init())
  goto bar_bye;

return TRUE;

bar_bye:
 bar_terminate();

foo_bye:
  foo_terminate();

bye:
  return FALSE;

@ Грег:

Почему бы не сделать ваш пример таким:

void foo()
{
    if (doA())
    {    
        if (doB())
        {
          if (!doC())
          {
             UndoA();
             UndoB();
          }
        }
        else
        {
          UndoA();
        }
    }
    return;
}

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

Adam Rosenfield 29.10.2008 07:45

Я бы взял отступы над goto в любое время.

FlySwat 29.10.2008 07:51

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

Patrick 29.10.2008 08:04

Я согласен с Патриком - я видел, как эта идиома использовалась с несколькими условиями, вложенными на глубину примерно 8 уровней. Очень противно. И очень подвержен ошибкам, особенно при попытке добавить что-то новое в микс.

Michael Burr 29.10.2008 09:33

Этот код просто кричит: «У меня будет ошибка через несколько следующих недель», кто-то забудет что-то отменить. Вам нужно, чтобы все ваши отмены находились в одном месте. Это похоже на «наконец» в родных объектно-ориентированных языках.

Ilya 29.10.2008 15:44

Мне не нравится повторение «UndoA ()» с копированием и вставкой. Код C'n'P примерно так же плох, как goto, и для меня в этом случае он проигрывает, потому что он более подробный. Также тот факт, что B делается после A, а также отменяется после A, заставляет мои зубы скручиваться, но это не часть шаблона здесь.

Steve Jessop 30.10.2008 03:51

Вы можете переписать это с меньшим вложением, выполнив if (! DoA ()) {return; } если (! doB ()) {UndoA (); возвращаться; } и так далее. У вас по-прежнему будут повторяющиеся вызовы функций, но, по крайней мере, код будет читабельным.

Tommy 30.10.2008 14:42

Почему вы не могли использовать здесь оператор case?

Austin 14.05.2009 19:34

@AlexandreC. А если под C работать, RAII отпадает и у вас goto >> эта хрень.

glglgl 20.11.2013 16:09

@ Остин: Это тоже возможно при определенных обстоятельствах. Правило должно быть таким: «Избегайте goto, если есть реальные альтернативы, но используйте его, когда это необходимо».

glglgl 20.11.2013 16:10

И сегодня я нашел отличную иллюстрацию того, как выглядит код пирамиды. msdn.microsoft.com/en-us/library/windows/desktop/…

Herrington Darkholme 08.02.2014 06:42

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

gnasher729 23.04.2014 18:13

@ fizzer.myopenid.com: размещенный вами фрагмент кода эквивалентен следующему:

    while (system_call() == -1)
    {
        if (errno != EINTR)
        {
            // handle real errors

            break;
        }
    }

Я определенно предпочитаю эту форму.

Хорошо, я знаю, что оператор break - это просто более приемлемая форма goto.

Mitch Wheat 29.10.2008 07:16

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

fizzer 29.10.2008 07:23

Назад? Он начинается, он продолжается, он проваливается. Думаю, эта форма более явно выражает свои намерения.

Mitch Wheat 29.10.2008 07:25

Я согласен с fizzer здесь, что goto дает более четкое представление о значении условия.

Marcus Griep 29.10.2008 07:48

Хорошо, нам придется не соглашаться по этому поводу.

Mitch Wheat 29.10.2008 07:51

+1, потому что версия while более ясна и избегает использования goto, которые имеют некоторые ограничения на прохождение через конструкцию объекта.

paercebal 29.10.2008 12:49

Чем легче читать этот фрагмент, чем fizzer?

erikkallen 26.12.2008 21:59

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

Eloff 30.07.2012 22:22

paercebal использует старый аргумент, что лучше избегать goto, потому что он избегает goto ... Я предполагаю, что он не совсем понимает значение errno == EINTR. Версия while совсем не яснее. Это создает совершенно неправильное впечатление, что у нас здесь есть цикл ожидания, который необходимо повторять, пока он не завершится успешно. Goto привлекает внимание читателя и заставляет его или ее фактически понимать кода.

gnasher729 23.04.2014 18:09

Очень распространенный.

do_stuff(thingy) {
    lock(thingy);

    foo;
    if (foo failed) {
        status = -EFOO;
        goto OUT;
    }

    bar;
    if (bar failed) {
        status = -EBAR;
        goto OUT;
    }

    do_stuff_to(thingy);

OUT:
    unlock(thingy);
    return status;
}

Единственный случай, когда я когда-либо использовал goto, - это прыгать вперед, обычно из блоков, а не в блоки. Это позволяет избежать злоупотребления do{}while(0) и другими конструкциями, которые увеличивают вложенность, сохраняя при этом читаемый структурированный код.

Я думаю, что это типичный способ обработки ошибок C. Я не вижу, чтобы он был заменен красиво, лучше читается в любом другом случае. С уважением

Friedrich 29.10.2008 09:25

Почему бы и нет ... do_stuff(thingy) { RAIILockerObject(thingy); ..... /* -->*/ } /* <---*/ :)

Петър Петров 22.04.2013 05:04

@ ПетърПетров Это шаблон в C++, не имеющий аналогов в C.

ephemient 22.04.2013 21:38

Или на еще более структурированном языке, чем C++, try { lock();..code.. } finally { unlock(); }. Но да, у C нет эквивалента.

Blindy 14.07.2014 23:23

Классическая потребность в GOTO в C заключается в следующем.

for ...
  for ...
    if (breakout_condition) 
      goto final;

final:

Нет простого способа выйти из вложенных циклов без goto.

Чтобы добавить к этому: способ сделать это без goto - это установить логический флаг и тестировать этот флаг на каждой итерации каждого внешнего цикла. Это создает менее читаемый код; он также немного менее эффективен, но актуален только в редких случаях (например, код ядра).

Adam Rosenfield 29.10.2008 07:47

Чаще всего, когда возникает такая необходимость, я могу использовать возврат. Но для этого нужно писать небольшие функции.

Darius Bacon 29.10.2008 08:50

Я определенно согласен с Дариусом - преобразовать его в функцию и вместо этого вернуть!

metao 29.10.2008 09:13

Johnathan - break выходит только из ближайшего цикла. Дариус - конечно. Но это классический пример Goto In C.

Paul Nathan 29.10.2008 09:55

@metao: Бьярн Страуструп не согласен. В его книге «Язык программирования C++» это как раз пример «правильного использования» goto.

paercebal 29.10.2008 12:45

@Adam Rosenfield: вся проблема с goto, выделенный Дейкстрой, заключается в том, что структурное программирование предлагает более понятные конструкции. Усложнение чтения кода во избежание перехода к goto доказывает, что автор не понял этого эссе ...

Steve Jessop 30.10.2008 03:43

Зачем вам финал в этом коде? Разбейте его на функцию.

Austin 14.05.2009 19:35

@Steve Jessop: Люди не только неправильно поняли эссе, но и большинство сектантов, которым "не идти", не понимают исторического контекста, в котором оно было написано.

JUST MY correct OPINION 23.04.2011 13:09

Этот случай очень редок и является единственным случаем, когда я действительно использую Goto, особенно если функция сложная и стек вызовов не должен быть перефреймирован! Другой - на stackoverflow.com/a/16137870/625904

Петър Петров 22.04.2013 04:57

@DariusBacon На самом деле return не всегда приносит удовольствие, потому что, если вы, например, выделили память или другие ресурсы, вы, вероятно, захотите освободить их перед возвратом, вот где goto великолепен.

Ignas2526 29.08.2013 15:54

@ Ignas2526 На самом деле возврата достаточно. если вы беспокоитесь об освобождении памяти, занимающей время выполнения, используйте встроенную функцию. если вы хотите сохранить значение, используйте указатели

Muhammad Annaqeeb 11.02.2014 07:42

Современные компиляторы @MuhammadAnnaqeeb игнорируют встроенные функции и имеют собственное мнение о встраивании функций, поэтому нет никаких гарантий. Допустим, вы выделяете A, делаете что-то, затем B, делаете что-то, затем C и так далее ... и в любой момент вы можете потерпеть неудачу, и вам нужно освободить только текущий и предыдущий, например если вы потерпите неудачу в B, вы освободите B и A, но не C и выше. В этом сценарии без goto вы получите тонну кода от встраивания или тонну вызовов функций.

Ignas2526 09.04.2014 15:58

Я на 95% уверен, что оператор return сгенерирует переход к концу функции, которую нужно вернуть (при условии, что у вас есть фрейм стека, который нужно свернуть), поэтому на самом деле это не отличается от использования goto, за исключением удобочитаемости исходного кода. Но, как уже указывалось, goto - это четырехбуквенное слово ...;)

krs013 19.04.2014 18:41

Несмотря на то, что со временем я возненавидел этот шаблон, он встроен в программирование COM.

#define IfFailGo(x) {hr = (x); if (FAILED(hr)) goto Error}
...
HRESULT SomeMethod(IFoo* pFoo) {
  HRESULT hr = S_OK;
  IfFailGo( pFoo->PerformAction() );
  IfFailGo( pFoo->SomeOtherAction() );
Error:
  return hr;
}

Я сам не использую goto, однако однажды я работал с человеком, который использовал бы их в определенных случаях. Если я правильно помню, его объяснение было связано с проблемами производительности - у него также были определенные правила для как. Всегда в одной и той же функции, и метка всегда была НИЖЕ оператора goto.

Дополнительные данные: обратите внимание, что вы не можете использовать goto для выхода за пределы функции, и что в C++ запрещено обходить построение объекта с помощью goto.

paercebal 29.10.2008 12:58

Кнут написал статью «Структурированное программирование с операторами GOTO», вы можете получить ее, например. из здесь. Вы найдете там много примеров.

Эта бумага выглядит глубокой. Я все же прочту это. Спасибо

fizzer 30.10.2008 01:09

Эта статья так устарела, это даже не смешно. Предположения Кнута здесь просто не актуальны.

Konrad Rudolph 29.06.2009 19:17

Какие предположения? Его примеры сегодня столь же реальны для процедурного языка, как C (он приводит их в некотором псевдокоде), как и в то время.

zvrba 29.06.2009 21:08

Я разочарован, что вы не написали :: Вы можете НАЙТИ 'здесь', чтобы получить это, каламбур для меня было бы невыносимым не сделать!

RhysW 08.01.2013 17:58

Я видел, как goto используется правильно, но ситуации обычно уродливые. Это только тогда, когда использование самого goto намного менее хуже оригинала. @Johnathon Holland проблема в том, что ваша версия менее ясна. люди, кажется, боятся локальных переменных:

void foo()
{
    bool doAsuccess = doA();
    bool doBsuccess = doAsuccess && doB();
    bool doCsuccess = doBsuccess && doC();

    if (!doCsuccess)
    {
        if (doBsuccess)
            undoB();
        if (doAsuccess)
            undoA();
    }
}

И я предпочитаю такие петли, но некоторые люди предпочитают while(true).

for (;;)
{
    //code goes here
}

Никогда и никогда не сравнивайте логическое значение с истиной или ложью. Это уже логическое значение; просто используйте "doBsuccess = doAsuccess && doB ();" и вместо этого "if (! doCsuccess) {}". Это проще и защищает вас от умных программистов, которые пишут такие вещи, как "#define true 0", потому что, ну, потому что они могут. Он также защищает вас от программистов, которые смешивают int и bool, а затем предполагают, что любое ненулевое значение истинно.

Adam Liss 23.12.2010 05:04

Спасибо и точка снята == true удалена. Во всяком случае, это ближе к моему настоящему стилю. :)

Charles Beattie 05.01.2011 22:30
#include <stdio.h>
#include <string.h>

int main()
{
    char name[64];
    char url[80]; /*The final url name with http://www..com*/
    char *pName;
    int x;

    pName = name;

    INPUT:
    printf("\nWrite the name of a web page (Without www, http, .com) ");
    gets(name);

    for(x=0;x<=(strlen(name));x++)
        if (*(pName+0) == '\0' || *(pName+x) == ' ')
        {
            printf("Name blank or with spaces!");
            getch();
            system("cls");
            goto INPUT;
        }

    strcpy(url,"http://www.");
    strcat(url,name);
    strcat(url,".com");

    printf("%s",url);
    return(0);
}

Другие вопросы по теме