Кресты / Говнокод #1775 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  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 из области видимости.
};

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

Запостил: Говногость Говногость, (Updated )

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

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

        Так что это не говнокод, а ошибочный код.
        Ответить
    • Предлагаю холивар на тему 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, дабы сделал результирующий код более эквивалентным 🙂
                  Ответить
  • Предлагаю начать холивар сновой строки, а то сильно в бок ушло...

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

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

        }

        ИМХО лучше поставить в конце функции метку и переходить туда в случае ошибки
        Ответить
        • тут можно использовать 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 и т.д. Функции не вызовешь, а то стек попортится...)
    Короче, кто за гото - тот долбоёб, кто против гото - тот тоже долбоёб.
    Ответить
  • Вы зачем эту фигню обсуждаете? Это не возможно.
    Ответить

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

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8