Re: Существуют ли задачи, где использование GOTO оправдано?
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.07.07 12:06
Оценка: 9 (1) +1 :)
Здравствуйте, Vedrus, Вы писали:

V>Люди, кто-нибудь может привести пример, где использование GOTO оправдано? Я знаю, что существуют такие задачи, но слабо представляю, как это в живую выглядит. Вроде в синтаксических анализаторах используется, и в очень сложных математических расчётах.


V>Сейчас практически все мои знакомые программисты считают, что использование GOTO – это признак кривизны кода. Хотелось бы их разубедить.


Goto — признак не кривизны кода, а кривизны языков, в которых без него порой никак (C, C++, C#, Pascal, Java, etc) и кривизны профанации под названием "структурное программирование" с его т.н. "циклами с предусловиями", "циклами с постусловиями" и "ветвлениями", которые являются не элементарными конструкциями, а типовыми паттернами, в которые задача не всегда удобно ложится.

Правда, пока для всяких Haskell не понаписали мегаоптимизаторов, Goto будет актульно для кодогенераторов в другие, более "низкоуровневые" языки.

Так что если кто-то пишет на C++ и вынужден юзать goto, пусть не стесняется, и посылает своих знакомых на 3 весёлых буквы. В конце концов, это не его вина. Кстати, виной K&R и Бьярни это тоже не является, т.к. это не они призывают в наш просвещённый XXI век всё и вся писать на C++ и (о боже!) на C.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[2]: Существуют ли задачи, где использование GOTO оправдан
От: Сергей Мухин Россия  
Дата: 31.07.07 12:42
Оценка:
K>Так что если кто-то пишет на C++ и вынужден юзать goto, пусть не стесняется, и посылает своих знакомых на 3 весёлых буквы. В конце концов, это не его вина. Кстати, виной K&R и Бьярни это тоже не является, т.к. это не они призывают в наш просвещённый XXI век всё и вся писать на C++ и (о боже!) на C.

Давайте на этой ноте и закончим. Или все бегом в "Свещенные войны"!!!
---
С уважением,
Сергей Мухин
Re: Существуют ли задачи, где использование GOTO оправдано?
От: last shinji  
Дата: 31.07.07 13:15
Оценка:
Здравствуйте, Vedrus, Вы писали:

V>Люди, кто-нибудь может привести пример, где использование GOTO оправдано? Я знаю, что существуют такие задачи, но слабо представляю, как это в живую выглядит. Вроде в синтаксических анализаторах используется, и в очень сложных математических расчётах.


V>Сейчас практически все мои знакомые программисты считают, что использование GOTO – это признак кривизны кода. Хотелось бы их разубедить.


Goto в MSDN. Встретилось однажды.
http://support.microsoft.com/kb/182888
Носок исчез в гильбертовом пространстве. Туда ему и дорога.
Re[4]: Существуют ли задачи, где использование GOTO оправдан
От: unreg_flex  
Дата: 31.07.07 13:26
Оценка: +2 -1
Здравствуйте, NikeByNike, Вы писали:

NBN>Ну дык он и так криво написан.


_>> for(int k=0;k<n3;++k) {

_>> if(come_condition2) goto next2;
_>> }
NBN>Должно быть вынесено в функцию (или скорее использована стандартная)
При чем тут стандартные функции?
В исходной функции 4 параметра +2 ссылки на структуру, и большинство из них используется
при вычислении come_condition1 и come_condition2, идиотизм ради отсутствия четырех символов 'goto'
заводить метод (или несколько методов) делающий непонятно что и с непонятно какими параметрами.

_>> for(int j = 0; j < n2; ++j) {

_>> if(come_condition1 || find_by_condition2)
_>> break;
_>> // some code
_>> }
NBN>Это тоже. Скорее всего оптимайзер это соптимайзит.
Дело даже не в оптимизации, а в том что каждое из условий может быть вычислено только там где оно стоит.

NBN>Сам по себе кусок кода — ужасен, сразу мысль — этот код нужно рефакторить.

Вот я и спросил у вас как?
Чем он ужасен в вашем понимании?
Приведите пример красивого рефакторинга Дабы увеличить читабельность кода.

NBN>Если это не критический участок кода — его нужно сделать красивее.

Опишите ваше понимание красоты (оно у всех разное).
Если критический — менять алгоритм.

Это критический участок кода, сложность N^3, предлагаете сделать за N^4?
Тут обычный перебор всех троек точек заданного множества с перестановками (алгоритм RANSAC для подбора кривой).
Ума не приложу, как это можно сделать по другому.

NBN>GOTO для отчистки кода — в 99.95% случаях самое что ни есть зло.

Откуда число 99.95%?, до боли знакомая рекламная константа
Как считали?
В чем заключается зло?

NBN>Нормальный программист будет использовать автоматику (конструкторы/деструкторы).

Нормальный программист будет писать понятно лаконично и эффективно.

NBN>GOTO для выхода из вложенных циклов? По хорошему эти циклы должны разноситься на отдельные функции.

Угу, обязательно на отдельные, даже когда во вложенных циклах используется десяток параметров.
Вы никогда не используете вложенных циклов?

NBN>Глядя на этот код — сразу появляется мысль, что у её авторов бывают функции больше чем на страницу и целый ряд прочих проблем.

Эта функция занимает меньше страницы, хотелось бы конкретизации "ряда прочих проблем".
Re[4]: Существуют ли задачи, где использование GOTO оправдан
От: unreg_flex  
Дата: 31.07.07 13:34
Оценка: +1
Здравствуйте, Кодт, Вы писали:

К>1) Если не зарубаться на то, что всё это должно лежать внутри одной функции, то можно переделать, раскидав циклы по функциям.

См пост для выше.
К>2) Булевы флажки.
Введение пачки булевых флажков и нескольких функций с кучей параметров несомненно увеличит, как читабельность, так понимание происходящего.

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

Это перебор по всем тройкам точек (модифицированный алгоритм RANSAC), с потолка ничего не взято и ошибок тут нет.

К>Потому что описания задач всё-таки тяготеют к иерархическим структурам (деревья принятия решений, рекурсивные формулы...), а граф конечного автомата — это результат трансляции.

Это банальный МатСтат
Re[5]: Существуют ли задачи, где использование GOTO оправдан
От: NikeByNike Россия  
Дата: 31.07.07 13:59
Оценка:
Здравствуйте, unreg_flex, Вы писали:

NBN>>Должно быть вынесено в функцию (или скорее использована стандартная)

_>При чем тут стандартные функции?
Вполне возможно что конечный цикл можно заменить на std::find_if или что то подобное.

_>В исходной функции 4 параметра +2 ссылки на структуру, и большинство из них используется

Этого не видно из исходного кода

_>при вычислении come_condition1 и come_condition2, идиотизм ради отсутствия четырех символов 'goto'

_>заводить метод (или несколько методов) делающий непонятно что и с непонятно какими параметрами.
Как раз наоборот. На то они и методы что понятно что делают, в отличии от готу. Названия надо нормальные давать.

NBN>>Сам по себе кусок кода — ужасен, сразу мысль — этот код нужно рефакторить.

_>Вот я и спросил у вас как?
Тебе кажется уже показали в соседнем ответе. Я показал тебе принципы рефакторинга, отдельные модули на которые нужно разделить код

_>Приведите пример красивого рефакторинга Дабы увеличить читабельность кода.

Уже приели

NBN>>Если это не критический участок кода — его нужно сделать красивее.

_>Опишите ваше понимание красоты (оно у всех разное).
Ну, тут тебе надо почитать классиков.

_>Это критический участок кода, сложность N^3, предлагаете сделать за N^4?

Я??? Где я предлагаю N4??? Я вообще не знаю что это за алгоритм и с какого перепугу это критический участок кода. Это кодек какой-то?

NBN>>GOTO для отчистки кода — в 99.95% случаях самое что ни есть зло.

_>Откуда число 99.95%?, до боли знакомая рекламная константа
_>Как считали?
Это прикидка — какая доля людей дрова пишет (0.05%).

_>В чем заключается зло?

Гм. А как у тебя с С++? Зачем нужны конструкторы/деструкторы? А смартпоинтеры?
Когда в последний раз один чел задавал подобный вопрос — выяснилось, что он со строками руками работал (char*, выделение и освобождение памяти ручками). Ты тоже этим страдаешь? Когда это возможно — исключения используешь? Контейнеры?


NBN>>Нормальный программист будет использовать автоматику (конструкторы/деструкторы).

_>Нормальный программист будет писать понятно лаконично и эффективно.
По твоему это типа так?
for(int i=0;i<n1;++i){for(int j=0;j<n2;++j){if(c1)goto next1;for(int k=0;k<n3;++k){if(c2)goto next2;}}next2:;}next1:;

Судя по отсуствию пробелов в for'ах действительно лаконично написано...
Я предпочитаю писать так чтобы хорошо читалось.


NBN>>GOTO для выхода из вложенных циклов? По хорошему эти циклы должны разноситься на отдельные функции.

_>Угу, обязательно на отдельные, даже когда во вложенных циклах используется десяток параметров.
Функторы?
_>Вы никогда не используете вложенных циклов?
Использую, правда два вложенных — это максимум на одну функцию и в дальнейшем это очень часто подвергается рефакторингу.

NBN>>Глядя на этот код — сразу появляется мысль, что у её авторов бывают функции больше чем на страницу и целый ряд прочих проблем.

_>Эта функция занимает меньше страницы, хотелось бы конкретизации "ряда прочих проблем".
Во-первых, я не сказал что-то конкретно про эту функцию. Я сказал, что глядя на стиль этой фунциии — начинаешь подозреать в плохом стиле и другие функции. К плохому стилю относятся длинные функции.
Во-вторых, это что всё тело функции??? Я так понимаю логика прогаммы помещена в operator bool() для come_condition1 и come_condition2?
Нужно разобрать угил.
Re[5]: Существуют ли задачи, где использование GOTO оправдан
От: Phoenics Россия https://sourceforge.net/projects/phengine
Дата: 31.07.07 14:18
Оценка: 4 (1) +1
Здравствуйте, Vedrus, Вы писали:

V>Вопрос не в том, что препод лох. Он мне аргументированно объяснил. Препод математик, и очень хорошо разбирается в структурном программировании. Бывает объективная необходимость во включении GOTO, для увеличения быстродействия. Мне бы хотелось услышать ответы от тех, кто считает, что GOTO имеет право на жизнь с конкретными примерами. Остальные не обижайтесь, но не надо писать сюда.




Конкретный пример привести не могу так как давно его забыл. Писал как-то переборщик паролей. Долго его оптимизировал разыми способами, так же у меня там был в цикле один оператор GOTO — дало по результатам профилировки VTune 30% прирост производительности. Конечно можно было написать цикл 100000-способов без GOTO, и я многие из них перепробовал, но из тех что я пробовал только этот дал столь существенный прирост.

Это был единственный раз в моей жизни, когда я использовал GOTO.

Вообще моё мнение такое — GOTO имеет право жить. Это такой же инструмент программирования как и любой другой, но этим инстурментом нужно ОЧЕНЬ аккуратно пользоваться, необходимость в нём возникает КРАЙНЕ редко. Я согласен с твоим преопдом что для оптимизации КРИТИЧНЫХ кусков кода, ИЗРЕДКА оператор GOTO может быть использован с пользой.

А вообще при программировании GOTO конечно является признаком кривизны кода. Знаю товарищей окторые пишут циклы, в циклах свичи километровые и в кейсах GOTO... Без целей оптимизации — просто так пишут... Код такой поддерживать просто кошмар.
---=== С наилучшими пожеланиями, Phoenics ===---
_
Re[6]: Существуют ли задачи, где использование GOTO оправдан
От: NikeByNike Россия  
Дата: 31.07.07 14:25
Оценка:
Здравствуйте, Phoenics, Вы писали:

P>Вообще моё мнение такое — GOTO имеет право жить. Это такой же инструмент программирования как и любой другой, но этим инстурментом нужно ОЧЕНЬ аккуратно пользоваться, необходимость в нём возникает КРАЙНЕ редко. Я согласен с твоим преопдом что для оптимизации КРИТИЧНЫХ кусков кода, ИЗРЕДКА оператор GOTO может быть использован с пользой.


P>А вообще при программировании GOTO конечно является признаком кривизны кода. Знаю товарищей окторые пишут циклы, в циклах свичи километровые и в кейсах GOTO... Без целей оптимизации — просто так пишут... Код такой поддерживать просто кошмар.


Подписываюсь.
Нужно разобрать угил.
Re[5]: Существуют ли задачи, где использование GOTO оправдан
От: Кодт Россия  
Дата: 31.07.07 15:32
Оценка:
Здравствуйте, unreg_flex, Вы писали:

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

_>Это перебор по всем тройкам точек (модифицированный алгоритм RANSAC), с потолка ничего не взято и ошибок тут нет.

Тогда остаётся первый вариант: этот код заоптимизирован
Дай, пожалуйста, ссылку на описание алгоритма. А то "come_condition" и "//some code" не очень отражают суть. То ли это хитрая отсечка, то ли хитрый поиск.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[6]: Существуют ли задачи, где использование GOTO оправдан
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.07.07 15:51
Оценка: 1 (1)
Здравствуйте, NikeByNike, Вы писали:

NBN>>>Должно быть вынесено в функцию (или скорее использована стандартная)

_>>При чем тут стандартные функции?
NBN>Вполне возможно что конечный цикл можно заменить на std::find_if или что то подобное.

Ага, map/filter/fold.

NBN>Как раз наоборот. На то они и методы что понятно что делают, в отличии от готу. Названия надо нормальные давать.


Названия внятные быстро заканчиваются, как раз после после do_that_mysterious_thing_2 и do_that_mysterious_thing_3.

NBN>Это прикидка — какая доля людей дрова пишет (0.05%).


А мне казалось, это ссылка на правило трёх сигм.

_>>В чем заключается зло?

NBN>Гм. А как у тебя с С++? Зачем нужны конструкторы/деструкторы? А смартпоинтеры?

Деструкторы нужны, потому что нет GC. Смартпоинтеры — потому же.

NBN>>>GOTO для выхода из вложенных циклов? По хорошему эти циклы должны разноситься на отдельные функции.

_>>Угу, обязательно на отдельные, даже когда во вложенных циклах используется десяток параметров.
NBN>Функторы?

Замыкания?

_>>Вы никогда не используете вложенных циклов?

NBN>Использую, правда два вложенных — это максимум на одну функцию и в дальнейшем это очень часто подвергается рефакторингу.



NBN>>>Глядя на этот код — сразу появляется мысль, что у её авторов бывают функции больше чем на страницу и целый ряд прочих проблем.

_>>Эта функция занимает меньше страницы, хотелось бы конкретизации "ряда прочих проблем".
NBN>Во-первых, я не сказал что-то конкретно про эту функцию. Я сказал, что глядя на стиль этой фунциии — начинаешь подозреать в плохом стиле и другие функции. К плохому стилю относятся длинные функции.

Сам когда-то в детстве (а это было как раз во время чтения мной рекомендаций по оформлению кода в GNU) страдал от подобных комплексов. Но после того, как изучил Scheme, быстро от них избавился. Это на Scheme и Haskell можно писать лаконично. А если нужно писать на C#, то нечего комплексовать, если метод занимает 200 строк. В конце-концов, есть комментарии, форматирование. Кроме того, сейчас столкнулся с такими задачами... Например, вычислительная геометрия. Где бы не смотрел исходники, везде получается длинно, так что сам не очень комплексую. Ах, как мне на работе не хватает Nemerle, с его вложенными функциями, замыканиями, лямбдами, map/filter/fold!
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[7]: Существуют ли задачи, где использование GOTO оправдан
От: NikeByNike Россия  
Дата: 31.07.07 16:20
Оценка:
Здравствуйте, konsoletyper, Вы писали:

_>>>В чем заключается зло?

NBN>>Гм. А как у тебя с С++? Зачем нужны конструкторы/деструкторы? А смартпоинтеры?

K>Деструкторы нужны, потому что нет GC. Смартпоинтеры — потому же.


Мы вроде-бы про С++ Кстати, с какого-то момента (когда в проекте не остаётся слова delete) нивелируется разница в программировании с GC и без него. А скорость программы остаётся.
Нужно разобрать угил.
Re[8]: Существуют ли задачи, где использование GOTO оправдан
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.07.07 16:55
Оценка: +1 -2
Здравствуйте, NikeByNike, Вы писали:

NBN>Мы вроде-бы про С++


А мне казалось — про goto.

NBN> Кстати, с какого-то момента (когда в проекте не остаётся слова delete) нивелируется разница в программировании с GC и без него. А скорость программы остаётся.


Вот я и говорю: смартпоинтеры нужны, потому что нет GC. А выделенное — ложь, т.к. GC гораздо быстрее смартпоинтеров, а managed heap — быстрее unmanaged heap. Да и проблем от этих смартпоинтеров куча. Начиная хотя бы с того, что нужно не забывать использовать именно их, а не воспользоваться сдуру обычным указателем.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[6]: Существуют ли задачи, где использование GOTO оправдан
От: unreg_flex  
Дата: 31.07.07 17:07
Оценка:
Здравствуйте, NikeByNike, Вы писали:

NBN>Этого не видно из исходного кода


Согласен, хотелось как проще а получилось как всегда, вот оригинал этого метода:

template< class ValueType >
void EstimateContour(
  const TGL::Point< ValueType,2 > *pPoints,
  int nPoints,
  const TGL::Polygon< ValueType,2 > &rPolygon,
  const CirclesCondition &rCirclesCond,
  const PointsCondition &rPointsCond) {

  msg_assert(nPoints>0,"Множество точек пусто");

  std::vector< TGL::Circle< ValueType > > Circles;
  TGL::Point< ValueType,2 > Inv1,Inv2;
  TGL::Circle< ValueType > c;

  Inv1=Inv2=pPoints[0];

  for(int i=0;i<nPoints;++i) {
    // отбрасываем точки вне оболочки
    if(!rPolygon.IsPointIn(pPoints[i])) continue;

    for(int j=i+1;j<nPoints;++j) {
      // первое условие двойственности
      if(!rCirclesCond.CheckFirst(pPoints[i],pPoints[j],rPointsCond)) goto next1;
      rPointsCond.Invert(Inv1,pPoints[j]);

      for(int k=j+1;k<nPoints;++k) {
        // второе условие двойственности
        if(!rCirclesCond.CheckSecond(pPoints[j],pPoints[k],rPointsCond)) goto next2;
        rPointsCond.Invert(Inv2,pPoints[k]);

        c.Estimate(pPoints[i],pPoints[j],pPoints[k]);
        c.Refine(Inv1,Inv2);
        // сохраняем если центр окружности принадлежит оболочке
        // и найденные параметры входят в заданный диапазон
        if(rPolygon.IsPointIn(c.Center())&&
           rCirclesCond.Check(c)) Circles.push_back(c);
      }
      
    }
    next2:;
  }
  next1:;
  EstimateHull(Circles,pPoints,nPoints);
}


NBN>Я??? Где я предлагаю N4??? Я вообще не знаю что это за алгоритм и с какого перепугу это критический участок кода. Это кодек какой-то?

Не совсем, но нечто подобное.

NBN>Это прикидка — какая доля людей дрова пишет (0.05%).

Дрова это теже программы, в которых также как и везде гото может встретится а может и не встретится.

NBN>Гм. А как у тебя с С++? Зачем нужны конструкторы/деструкторы? А смартпоинтеры?

NBN>Когда в последний раз один чел задавал подобный вопрос — выяснилось, что он со строками руками работал (char*, выделение и освобождение памяти ручками). Ты тоже этим страдаешь? Когда это возможно — исключения используешь? Контейнеры?
Нееее, мы ничего такого не используем, все пишем только в машинных кодах
А если серьезно:
boost мы не юзаем, из того что нам требуется там почти ничего нет.
stl используем везде где это возможно, однако до сих пор ни у кого в коде даже не нашлось нормальное применение обычным спискам из стл.
Либо количество элементов очень невелико (порядка 10-20) и можно обойтись обычным вектором или использовать массив указателей,
либо оно велико и можно легко найти верхнюю оценку, других случаев почему-то небыло.
А как только нужно реализовать какой-нибудь специализированный геометрический алгоритм (к примеру),
то для него не подходит ни один из стандартных контейнеров стл, и приходится все писать самим (например N мерный кластер точек).
Исключения не используем вообще, и более того, открою страшный секрет
Мы два года назад отказались от проверок на ошибки выделения памяти
И с тех пор ни разу, ни одна из наших програм не упала по этой причине.
А насчет смартпоинтеров скажу:
COM мы не используем (не та область разработки), хотя иногда бывает, ну например MSXML подключить.
А других применений для него так и не нашлось.
Однажды, очень давно, на старом месте работы (не скажу где) люди шарахались с ужасной гримасой от строчки вида: SomeType *p;
И пихали смартптры везде где только можно их запихнуть, но от этого количество багов почемуто не уменьшалось.
По сути все эти биндеры смартптры итераторы (которые на самом деле вовсе не итераторы) фишки из буста (я не имею ввиду алгоритмы)
и прочая хренотень есть большой набор костылей призванный хоть как-то внести в язык отсутствующую функциональность.
Лично мое мнение таково, если ее там нет, то нечего и рыпаться, а если она нужна, то надо выбирать язык по ее наличию.

NBN>>>Нормальный программист будет использовать автоматику (конструкторы/деструкторы).

А кто их не использует при программировании на С++?

NBN>По твоему это типа так?

NBN>
NBN>for(int i=0;i<n1;++i){for(int j=0;j<n2;++j){if(c1)goto next1;for(int k=0;k<n3;++k){if(c2)goto next2;}}next2:;}next1:;
NBN>

Не надо утрировать, ни я, ни кто-либо из нашей команды такого не писал.
NBN>Судя по отсуствию пробелов в for'ах действительно лаконично написано...
Пробелы в форах это так?: for ( int i = 0; i < n; ++i ) { }
Что я могу тут сказать, в нашем отделе работает 6 человек и многие пишут по разному:
Например так:
for( int i = 0; i < n; ++i )
{
}

Так:
for( int i=0; i<n; ++i ) {
}

Или так:
for(int i=0;i<n;++i)
{
}

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

NBN>Я предпочитаю писать так чтобы хорошо читалось.

Аналогично.

NBN>>>GOTO для выхода из вложенных циклов? По хорошему эти циклы должны разноситься на отдельные функции.

NBN>Использую, правда два вложенных — это максимум на одну функцию и в дальнейшем это очень часто подвергается рефакторингу.
Параноидальное разнесение вложенных циклов на функции?

NBN>Функторы?

К сожалению далеко не всегда они применимы, в некоторых случаях с ними получается просто адское месиво.

NBN>Ну, тут тебе надо почитать классиков.

Читали мы и классиков и современников.

NBN>названия надо нормальные давать... вполне возможно можно заменить... принципы рефакторинга... отдельные модули...

Это мы все видели и слышали, теперь я привел полную версию метода. Напишите этот метод как считаете нужным. И сравним читабельность

PS Любые, даже самые хорошие советы содержат исключения. Тем же свойством обладают и советы в книгах.
Поэтому если пишут что делать нужно так и сяк, то это вовсе не значит что надо поступать именно так и именно сяк фанатично и всегда.
Re[6]: Существуют ли задачи, где использование GOTO оправдан
От: unreg_flex  
Дата: 31.07.07 17:15
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, unreg_flex, Вы писали:


К>Дай, пожалуйста, ссылку на описание алгоритма. А то "come_condition" и "//some code" не очень отражают суть. То ли это хитрая отсечка, то ли хитрый поиск.


Оригинальная процедура
Автор: unreg_flex
Дата: 31.07.07
Re: Существуют ли задачи, где использование GOTO оправдано?
От: Нэчер  
Дата: 31.07.07 21:21
Оценка:
Здравствуйте, Vedrus, Вы писали:

V>Люди, кто-нибудь может привести пример, где использование GOTO оправдано? Я знаю, что существуют такие задачи, но слабо представляю, как это в живую выглядит. Вроде в синтаксических анализаторах используется, и в очень сложных математических расчётах.


V>Сейчас практически все мои знакомые программисты считают, что использование GOTO – это признак кривизны кода. Хотелось бы их разубедить.


Не надо их переубеждать. Возможно они считают данный стиль "плохим", потому что сами используют "хороший". Значит нашли удобный лично для себя набор правил, позволяющий минимизировать количество ошибок в коде.
Я вот еще слышал мнение, будто return не из конца метода, а также использование "do{ }while(...);" это тоже плохой стиль... Ну и на здоровье!

Касаемо GOTO:

1)Вот, для примера, ф-ия аналог strstr для поиска одной подстроки внутри другой:

const char* strnstr(const char* pStr,int nStrLength,const char* pSubStr,int nSubStrLength)
{
    nStrLength-=nSubStrLength;
    for(int i=0;i<=nStrLength;++i,++pStr)
    {
        for(int j=0;j<nSubStrLength;++j)
           if(pSubStr[j]!=pStr[j]) goto NEXT;//a)Можно было бы использовать "break"

        //b)А здесь мог бы быть "if(j>=nSubStrLength)"
        return pStr;

        NEXT:;//c)Ну и само собой, этой метки здесь тоже могло бы не быть
    }
    return 0;
}

В данном конкретном случае, goto выглядит как более изящное решение: оно не ухудшило читаемость кода + позволило сэкономить на операции сравнения, выполняемой в цикле. Использовать или нет — вопрос религии.

2) Есть один замечательный трюк с метками (помню, что точно работало в VC6.0):

bool add(int a,int b,int& c)
{
  c=a+b;

  //А теперь проверим - было ли переполнение?
  __asm
  {
    jc CarryFlag 
  }

  //no carry
  return 0;

  CarryFlag:;

  //carry
  return 1;
}


Если подойти к вопросу трезво, то можно о-го-го сколько наоптимизировать в разного рода вычислительных алгоритмах =)
Re[2]: Существуют ли задачи, где использование GOTO оправдан
От: Programador  
Дата: 31.07.07 21:37
Оценка:
Здравствуйте, _pk_sly, Вы писали:

__>1. выход из вложенных if/switch/while на нужный уровень.


__>2. сгенерированные конечные автоматы зачастую этим пользуются для перехода между состояниями

однозначно

pozicionN:
///////
switch()
{  case 1: goto pozicion1;
///////////////////////
}

__>3.
__>
__>for (...) {
__>  if (...) break;
__>}
__>// а тут надо что-то сделать в случае, если выход из цикла был не по break
__>


вообщето можно так
for(... ;; ...)
{  if(end())
   { /* а тут надо что-то сделать в случае, если выход из цикла был не по */      break;
   }
   .................
   if (...) break;
   ..............
}

насчет читабельности но метку ставить не нужно

__>4. выполнение cleanup-кода перед выходом из функции



__>disclaimer: я не призываю всегда в этих случаях пользоваться goto




Теперь про функции, собственно 2 АЛЛ


void foo()
{  DoSDELATb_VSE();
   DoSDELATb_IS4E_RAZ();
   DoZAKON4ITb();
}

Если ктото скажет что этот код нечитабельный, он будет не прав. Но если ктото скажет что он читабельный он тоже будет неправ.

Дело в следующем — тут ровно 2 случая.
Либо этот код работает, тогда он читабельный. Но в этом случае мне не назачем ненужно его читать.
Либо он не работает, тогда нужно лазить досконально во все Do и он ну совсем не читабельный
Re: Существуют ли задачи, где использование GOTO оправдано?
От: Пётр Седов Россия  
Дата: 31.07.07 21:53
Оценка:
Здравствуйте, Vedrus.
Есть два очень разных случая.

1. goto назад. Это плохой способ сделать цикл, например:
Connect:
  ...
  goto Connect;

last shinji привёл ссылку на такой код здесь
Автор: last shinji
Дата: 31.07.07
.

2. goto вперёд. Это нормально, примеры (для C++):
* return в середине функции – досрочно завершить выполнение функции и передать управление на строчку за вызовом функции.
* break в цикле – досрочно завершить выполнение цикла и передать управление на строчку за циклом.
* continue – досрочно завершить выполнение итерации цикла и передать управление на следующую итерацию. А если следующей итерации нет, то передать управление на строчку за циклом.
* throw (и longjmp) – досрочно завершить выполнение кода (обычно из-за аварии) и передать управление обработчику исключения (блок catch).

Например, Фредерик Брукс в книге «Мифический человеко-месяц»
Автор(ы): Фредерик Брукс
Эта книга — юбилейное (дополненное и исправленное) издание своего рода библии для разработчиков программного обеспечения во всем мире, написанное Бруксом еще в 1975 году. Тогда же книга была издана на русском языке и давно уже стала библиографической редкостью. В США полагают, что без прочтения книги Брукса не может состояться ни один крупный руководитель программного проекта. Если вы никогда не слышали об этой книге, вы можете поискать ссылки на нее в Интернете (Frederick P. Brooks, The Mythical Man-Month). Вам все сразу станет понятно.
пишет (здесь):

Глава 13. Целое и части

Проектирование без ошибок

Структурное программирование

В основе, несомненно, лежат здравые мысли. При обсуждении сделано много критических замечаний — в частности, большое удобство представляют дополнительные управляющие структуры, такие как n-вариантный переход (так называемый оператор CASE) для различения среди нескольких случаев и аварийный выход (GO TO ABNORMAL END). Кроме того, некоторые догматически избегают всех GO TO, что представляется чрезмерным.

Пётр Седов (ушёл с RSDN)
Re[2]: Существуют ли задачи, где использование GOTO оправдан
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 31.07.07 21:56
Оценка: 1 (1)
Здравствуйте, Нэчер, Вы писали:

Н>Не надо их переубеждать. Возможно они считают данный стиль "плохим", потому что сами используют "хороший". Значит нашли удобный лично для себя набор правил, позволяющий минимизировать количество ошибок в коде.


+1. Вообще, поиск и применение правильных удобных шаблонов — крайне важная часть работы и построения своего опыта, даже если использует столь "нелюбимые" средства.

Н>Я вот еще слышал мнение, будто return не из конца метода, а также использование "do{ }while(...);" это тоже плохой стиль... Ну и на здоровье! :xz:


Это мнение, кстати, основывается на том, что break, continue и return — это те же goto. По сути так и есть, и если уж исходить из позиций "структурного" программирования полностью, то их не должно быть. Одна точка входа — одна точка выхода. Внутри — линейное выполнение, ветвления и циклы. Всё что за пределами этого подхода — уже резко усложняется в доказательстве.

Но есть ещё один момент (известный, но в данном треде вроде не звучал). Дело в том, что break, continue, return, а за компанию и throw — являются формами goto, ограниченными в действии наружу блока (включая тело функции). Поэтому, даже если они влияют на часть доказательности (например, о соблюдении инвариантов в теле цикла) — они не вводят таких грубых ситуаций, как переход внутрь цикла без прохождения пролога цикла. goto же, в отличие от них, в языках типа Си не имеет языковых ограничений подобного рода (ни синтаксически, ни в обязательном или рекомендованном анализе семантики). Поэтому его проблемы не в выходе из вложенных циклов, а в значительно более извращённых применениях, которые я упомянул и которые наверняка не приходят в голову апологетам его отсутствия:)

Единственный компилятор, про который я точно знаю, что он жёстко запрещал такие действия, как переход внутрь цикла или ветки if'а — Microsoft Fortran версии как минимум с 4-й.

Я лично отношусь к goto достаточно лояльно, по крайней мере в пределах определённых шаблонов использования:
1. Завершение работы функции с освобождением занятого и возвратом изменённого, для избежания дублирования кода по освобождению/очистке/возврату (потому что такое дублирование приводит к ошибкам в ~99% написаний).
2. Близко к первому — постепенный откат изменений в том случае, если действий много, откатывать их надо в обратном порядке, а вложенность в случае структурного написания получится чрезмерной.
3. Почти на ту же тему — объединение веток завершения функции, но не с очисткой, а с сообщением об ошибке.
4. Выход из глубокой вложенности циклов или if'ов на выделенную ветку выполнения или сразу за конец внешнего из покинутых циклов.
5. Переход (обычно только вперёд) по длинной линейной последовательности действий, строить которую в виде ветвлений или автомата (while+switch) означает нарушить восприятие кода.
6. Как типичный вариант (5) — backtracking в некоторых исполнениях.

Но при наличии более продвинутых средств, чем голый Си, 1-3 можно перевалить на классы и RAII;
с четвёртым хуже — throw/catch здесь как из пушки по воробьям. В некоторых языках есть средства вроде "break 2" или "break название_цикла" (первое — например, sh, второе — Perl),
а там где их нет — увы, goto или throw.

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

Н> //А теперь проверим — было ли переполнение?

Н> __asm
Н> {
Н> jc CarryFlag
Н> }

Ну это уже совсем спецхак:))
The God is real, unless declared integer.
Re[3]: Существуют ли задачи, где использование GOTO оправдан
От: Programador  
Дата: 31.07.07 22:21
Оценка:
Здравствуйте, netch80, Вы писали:

N>обосновывать и стараться применять пореже — их неудобно поддерживать. А если мы при этом обходим, например, инициализации переменных — такое писать нельзя ни в коем случае.

А и не позволят, если они конечно локальные. Деструкторы же по goto наружу кажется зовутся
Re[2]: Существуют ли задачи, где использование GOTO оправдан
От: Programador  
Дата: 31.07.07 22:30
Оценка:
Здравствуйте, Нэчер, Вы писали:

Н>
Н>  c=a+b;

Н>  //А теперь проверим - было ли переполнение?
Н>  __asm
Н>  {
Н>    jc CarryFlag 
Н>  }

Н>}
Н>

За это 5 баллов! А если кому не понравится пусть напишет проверку на переполнение в рамках стандарта
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.