1. C++ / Говнокод #1775

    +61.1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    void funcMir()
    {
    
    ...
    
    if ( __mir0>5 )
    goto vihod;
    TMir1 __mir1; // Конструктор не вызывается. (Оператор goto перескакивает через него.)
    
    ...
    
    vihod:
    ...
    // Здесь вызывается деструктор для __mir1 при выходе __mir1 из области видимости.
    };

    Код оригинальный из инета. Комментарии добавил мой друг.

    Запостил: Говногость, 06 Сентября 2009

    Комментарии (45) RSS

    • враньё
      Ответить
    • Емнип, обычно компиляторы на таком goto ошибку выдают.
      Ответить
    • По-моему, ерунда. Деструктор вызывается при очищении стека функции, а так как переменная не создавалась, ее нет в стеке, соответственно и деструктор не должен вызываться.
      Ответить
      • оно тупо не компилится
        неужели кто-то думает, что в плюсовых компайлерах
        остался бы такой баг и был "случайно" каким-то нубом?
        Ответить
        • Ну если в классе находятся только встроенные типы, и тривиальный деструктор, а конструктор проводит инициализацию какого-либо поля специальным значением, то goto может перескочить через него, оставив объект неинициализированным. Но компилятор обязан выдать warning.
          Ответить
        • Проверил. Действительно, не компилится:
          jump to label ‘vihod’ from here crosses initialization of ‘TMir1 __mir1’

          Так что это не говнокод, а ошибочный код.
          Ответить
          • На каком компиляторе компилил?
            Ответить
            • g++ 4.3.2
              Ответить
              • Может какие старые компиляторы и остались с такой ошибкой, но сейчас современные, видать, уже не встретишь с таким недочетом.
                Ответить
          • Это ошибочный говнокод
            Ответить
    • Отправить goto в помойку...
      Ответить
      • Предлагаю холивар на тему goto
        Вопрос для начала: как без goto делать break из вложенниго цикла?
        Ответить
        • Загонять циклы в функцию и делать возврат.
          Ответить
          • Хорошо, вопрос посложнее.
            Есть три вложенных цикла. В зависимости от обстоятельств надо делать выход из среднего или внешнего. Как?
            Ответить
            • Вложенными функциями. Чтобы локальные переменные не передавать, обернуть все в класс.
              Это если уж решительно идти без goto.
              Ответить
              • Кажется мы говорим про разные вещи.

                while(...) {
                  ...
                  while(...) {
                    ...
                    while(...) {
                      ...
                      if(...)
                        goto endmiddle;
                      else
                        goto endouter;
                      ...
                    }
                    ...
                  }
                  endmiddle:
                  ...
                }
                endouter:

                Если goto на помойку, то как это переписать без значительного усложнения?
                Ответить
                • >Если goto на помойку, то как это переписать без значительного усложнения?

                  очень просто - вообще не писать такое
                  три вложенных цикла - говнокод по определению

                  зы. я - другой guest, если что
                  Ответить
                • int Func( ... )
                  {
                  while( ... )
                  {
                  while( ... )
                  {
                  if( ... )
                  return END_MIDDLE;
                  else
                  return END_OUTER;
                  }
                  }
                  return END;
                  }

                  ...
                  while(...)
                  {
                  int Res = Func( ... );
                  if( Res == END_OUTER )
                  break;
                  }
                  ...

                  Вроде бы усложениния не такие значительные. Мм?
                  Ответить
                  • Имхо, значительные. Но главное что они есть и значит goto в данном случае оправдан. Например, создатели Java прежде чем выкинуть goto ввели break на метку. В C++ этого нет (а также нет finally) и говорить про отказ от goto не приходится
                    Ответить
                    • никто от goto не отказывался, просто это плохая практика программирования.
                      goto часто сильно усложняет процесс разбора и поддержку кода.
                      всегда можно написать без него. приведите, плиз, реальный пример, когда goto необходим, ибо три вложенных цикла с неясными условиями завершения - шибко надумано, да и в них можно без него.
                      Ответить
                      • Да не, иногда приходится экономить каждый такт в некоторых кусках кода, где действительно очень сложное поведение. Я хоть сам плохо отношусь к goto, но иногда использую.
                        Ответить
                  • еще более реальный пример:
                    хотя он более Си-ориентированный
                    void func( /*тут гдет 10 аргументов, поинтеры на различные структуры*/)
                    {
                    some_type val = init_by_arg1(arg1);
                    if(val)
                    {
                    cleanup(arg1);
                    }
                    //....... и так со всеми

                    some_action_with_some_val( val_9 );
                    // и потом очитка
                    }
                    надеюсь понятно проблему?

                    в плюсах бы решалось написанием классов с детрукторами, но тоже не всегда удобно, если нужные функции портируются из Сишных либ
                    Ответить
                    • > в плюсах бы решалось
                      а это и есть раздел про плюсы

                      > но тоже не всегда удобно, если нужные функции портируются из Сишных либ

                      а в чем проблема?
                      приведенный код - не более, чем плохое проектирование, как мне отсюда кажется
                      Ответить
                  • Надо бы добавить inline к Func, дабы сделал результирующий код более эквивалентным :)
                    Ответить
        • Оператором break и делать
          Ответить
    • Предлагаю начать холивар сновой строки, а то сильно в бок ушло...

      Мне кажется, что goto - незаменим в некоторых случаях. Все другие методы в ЭТИХ случаях только ухудшают читабильность и уменьшают скорость исполнения программы.
      Ответить
      • Ты не прав
        Ответить
        • Вот пример:

          bool func()
          {
          ...
          if (ошибка)
          {
          //делаем ряд действий
          return false;
          }
          //и этот блок встречается еще не раз

          }

          ИМХО лучше поставить в конце функции метку и переходить туда в случае ошибки
          Ответить
          • ScopeGuard вам в помощь
            Ответить
          • тут можно использовать try, catch и throw вместо goto

            а если без них то берем переменную int stage = 0; после каждого шага наращиваем, если произошла ошибка, то загоняем эту переменную в switch и выполняем действия обратные сделанным.
            пример

            int stage = 0;

            ptr1 = new Obj1();
            error = ptr1 == NULL;
            if (!error)
            {
            stage++;
            ptr2 = new Obj2();
            error = ptr2 == NULL;

            if (!error)
            {
            stage ++;

            .............
            }
            }

            .....

            if (error)
            {
            switch(stage)
            {
            case 2:
            delete ptr2;
            case 1:
            delete ptr1;
            }
            }
            то есть goto я бы не использовал ни при каких обстоятельствах, и еще ниразу не встречал код который нельзя переписать без goto
            Ответить
            • ужас.
              Ответить
            • > еще ниразу не встречал код который нельзя переписать без goto

              Никто не встречал и не встретит.
              Идея структурного программирования как раз и основана на том, что любой алгоритм можно закодировать в виде комбинации последовательного выполнения, ветвления и цикла. Это давно доказано, и не надо изобретать вечный двигатель. Но вопрос в другом: действительно ли оправдан отказ от goto.
              Ответить
              • > Но вопрос в другом: действительно ли оправдан отказ от goto.

                если бы от него отказались, то не было бы такого keyword'a :)
                пользуйтесь наздоровье и надейтесь, что это не выйдет боком впоследствии.
                к счастью, в промышленном коде - goto редкостная редкость.
                зато в говноопенсорсе часто вижу :( в общем, как и хреновое форматирование и имена переменных вида s, ss, a, b и иже с ними.
                Ответить
                • > если бы от него отказались, то не было бы такого keyword'a

                  В джаве нет оператора goto, но есть ключевое слово goto
                  Видимо, создатели сами не были уверены в успехе отказа :)
                  Ответить
                • >в говноопенсорсе часто вижу
                  а в проприетарщине и не увидишь
                  Ответить
              • А вы как бы не забыли как на самом деле циклы работают?
                есть мнение, что именно гоу ту и делают циклы
                Ответить
            • >тут можно использовать try, catch и throw вместо goto

              случайно не так:
              try
              {
              if(!val)
              {
              // ...............
              throw 1;
              }
              /// do some
              if(!val2)
              {
              // ...............
              throw 2;
              }
              //.............
              }
              catch
              {
              //some cleanup
              }
              (:
              Ответить
              • > случайно не так:
                еще ужаснее, чем предыдущий пример.
                и медленнее.
                вообще это неправильное использование exceptions :)
                Ответить
            • Да... Это пиздец...
              Ответить
            • ммм, прекрасная идея использовать экспешны вместо гоу ту, идите на сшарп, пожалуйста
              Ответить
          • незнаю, таких "некоторых" случаев не встречал. Сколько пишу, даже на мысль о гото не наталкивался, слава богу плюсы ООП язык, шаблоны, классы, функции, полиморфизмы... а гото? куда его?

            для обработки ошибок и их последствий есть авто-птр, деструкторы, эксепшны, функции, но гото практически всегда наводит на мысль о кривости кода :)
            Ответить
      • Мое личное мнение - goto в С++ нужен из-за отсутствия try..finally блоков и невозможности выхода во внешний цикл из внутреннего при помощи break или continue.
        Конечно, лучше максимально избегать использования goto - рефакторить код и т.д.
        Ответить
    • Пишу в Plain C, и там тоже не использую goto практически нигде. Но и полностью отказываться от него по причинам идеологическим тоже глупо - вон какой говнокод вверху приводили - медленный, нечитаемый, и громоздкий, лишь бы не писать двух строчек гото. Вообще-то гото плох когда он всё время, а не когда он один раз в виде исключения на тысячу случаев.
      Иногда приходится его использовать в очень сложных случаях (опять же, например, когда используются макросы va_start и т.д. Функции не вызовешь, а то стек попортится...)
      Короче, кто за гото - тот долбоёб, кто против гото - тот тоже долбоёб.
      Ответить
    • Вы зачем эту фигню обсуждаете? Это не возможно.
      Ответить

    Добавить комментарий