Примеры хороших 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();" и вм ...