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

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

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

infinite_loop: // code goes here goto infinite_loop; 

Почему 9X_c++ это лучше, чем альтернативы:

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

Правила:

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

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

Изменить

На 9X_cxx этом вопрос, кажется, закончен. Это дало 9X_goto несколько качественных ответов. Спасибо 9X_c++ всем, особенно те, кто серьезно относился 9X_cxx к моему примеру с петлей. Большинство скептиков 9X_cpp были обеспокоены из-за отсутствия рамки 9X_cxx блока. Как отметил @quinmars в комментарии, вы 9X_cxx всегда можете поставить фигурные скобки 9X_cxx вокруг тело петли. Попутно отмечу, что for(;;) и 9X_cxx while(true) не дают вам фигурных скобок бесплатно (и 9X_c их пропуск может вызвать досадные ошибки). В 9X_goto любом случае, я больше не буду тратить впустую из 9X_c ваших умственных способностей на эту пустяк 9X_goto - я могу жить с безобидными и идиоматическими 9X_cpp for(;;) и while(true) (с тем же успехом, если я хочу сохранить 9X_goto свою работу).

Учитывая другие ответы, я вижу, что 9X_c++ многие люди рассматривают goto как то, что вы 9X_cpp всегда придется по другому переписать. Конечно, вы 9X_goto можете избежать goto, введя цикл, дополнительный 9X_cxx флаг, стек вложенных if или чего-то еще, но 9X_goto почему бы не подумать, является ли goto возможно 9X_cpp лучший инструмент для работы? Другими словами, на 9X_c сколько уродства готовы вынести люди, чтобы 9X_c++ избежать использования встроенной языковой 9X_goto функции по прямому назначению? Я считаю, что даже 9X_c установка флага - слишком высокая цена. Мне 9X_goto нравится, когда мои переменные представляют 9X_cpp вещи в области проблемы или решения. "Исключительно, чтобы 9X_goto избежать goto" не сокращает его.

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

80
6

  • Я согласен с тем, что «goto» может быть полезным (ниже приведены отличные примеры), но я не согласен с вашим конкретным примером. Строка с надписью «goto infinite_loop» звучит так, как будто она означает «перейти к той части кода, где мы собира ...
12
Общее количество ответов: 12

Ответ #1

Ответ на вопрос: Примеры хороших gotos на C или C++

Вот одна уловка, которую я слышал от людей. Хотя 9X_cxx я никогда не видел его в дикой природе. И 9X_cpp это применимо только к C, потому что в C++ есть 9X_goto 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; } 

87
8

  • Что в этом плохого? (кроме того факта, что комментарии не понимают ...

Ответ #2

Ответ на вопрос: Примеры хороших gotos на C или C++

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

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

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

85
9

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

Ответ #3

Ответ на вопрос: Примеры хороших gotos на C или C++

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

restart: if (system_call() == -1) { if (errno == EINTR) goto restart; // handle real errors } 

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

32
6

  • @Amarghosh, `continue` - это прос ...

Ответ #4

Ответ на вопрос: Примеры хороших gotos на C или C++

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

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); } } 

приведенный выше код из 9X_goto Википедии entry.

14
8

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

Ответ #5

Ответ на вопрос: Примеры хороших gotos на C или C++

Кнут написал статью "Структурированное 9X_c++ программирование с помощью операторов GOTO", вы 9X_cpp можете получить ее, например из here. Там вы 9X_c найдете множество примеров.

14
3

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

Ответ #6

Ответ на вопрос: Примеры хороших gotos на C или C++

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

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

12
2

  • is inf_loop: {/ * тело ...

Ответ #7

Ответ на вопрос: Примеры хороших gotos на C или C++

Очень часто.

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; } 

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

12
2

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

Ответ #8

Ответ на вопрос: Примеры хороших gotos на C или C++

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

if (!openDataFile())
  goto quit;

if (!getDataFromFile())
  goto closeFileAndQuit;

if (!allocateSomeResources)
  goto freeResourcesAndQuit;

// Do more work here....

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

7
1

  • Если вы создали эти 3 дополнительные функции, вам нужно будет передать указатели / дескрипторы ресурсов и файлов, которые нужно освободить / закрыть. Вы, вероятно, заставили бы freeResourcesCloseFileQuit() вызвать closeFileQuit(), ко ...

Ответ #9

Ответ на вопрос: Примеры хороших gotos на C или C++

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

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

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

7
5

  • Хорошо, я знаю, что операт ...

Ответ #10

Ответ на вопрос: Примеры хороших gotos на C или C++

Несмотря на то, что со временем я возненавидел 9X_c++ этот шаблон, он встроен в программирование 9X_goto 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; } 

6
0

Ответ #11

Ответ на вопрос: Примеры хороших gotos на C или C++

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

// No Code 

9X_c

5
2

  • Это не очень полезно<p><span c ...

Ответ #12

Ответ на вопрос: Примеры хороших gotos на C или C++

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

void foo() { bool doAsuccess = doA(); bool doBsuccess = doAsuccess && doB(); bool doCsuccess = doBsuccess && doC(); if (!doCsuccess) { if (doBsuccess) undoB(); if (doAsuccess) undoA(); } } 

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

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

1
1

  • Никогда и никогда не сравнивайте логическое значение с истиной или ложью. Это уже логическое значение; просто используйте "doBsuccess = doAsuccess && doB();" и вм ...