goto vs ...
label 1;
var i:integer;
begin
prost:=true;
for i:=2 to num div 2 do
if num mod i = 0 then begin prost:=false; goto 1 end;
1:
end;
Не понял? А какая необходимость goto в if втыкать.
Во-первых там можно break поставить (выход из цикла).
Во-вторых там вообще надо уже exit'ом из ф-и выходить.
P.S. Это так - к слову.
Не, скорее всего, в этом нет ничего плохого... но мне лично самому всё это не нравится))) Мне не понятно идея гоуту, если в любой ситуации (с которой я встречался) можно обойтись циклами.
А я вот встречался. Я не сторонник Goto.
Но я за его разумное использование!
Например какую-то прогу(игру). В конце спрашиваеш - начать сначала(Yes/No)? Если Yes то перебрасываеш в начало.
Вот в таких местах и разумно ставить goto.
Но не надо им злоупотреблять!
Лучше использовать Repeat/While чем везде понатыкивать goto.
У КАЖДОГО ИЗ НИХ ЕСТЬ СВОЕ МЕСТО!
Ха... где-то кто-то считает что goto суть плохо.....
Если бы это было так, то такого оператора просто не существовало бы....
GOTO нужен....
и зачастую позволяет СОКРАТИТЬ и повысить УДОБОЧИТАЕМОСТЬ кода в разы....
Единственный момент -- не прыгать !!В!! функции и циклы, а из них пожалуйста...
ты прав, goto это jmp в асме
и поэтому goto не bad и не good
и поэтому goto не bad и не good
Однако практически его использовать не стоит, если программируешь не на асме. Асм, если что - другая концепция разработки кода, оттого там и используется goto. В обычных ПО- и ОО-языках использование goto считается плохим тоном, поскольку там всегда можно обойтись циклами, if-ами и т.п. Если кажется, что нельзя - достаточно хорошо подумать, и получится!
Кроме прочего, в некоторых современных языках слово goto зарезервировано, но ничего не делает. Поэтому писать с goto - плохая привычка.
Кстати, по аналогичным причинам плохая привычка всуе употреблять такие конструкции, как RaiseEvent, хотя очень часто бывает, что от этого никуда не денешься; я как раз сейчас разгребаю такой код.
Так тоже нельзя..... Если надо выкопать большую яму можно использовать экскаватор, а можно "достаточно хорошо ПОРАБОТАТЬ, и получится!"... выкопать эту яму лопатой....
Дествительно ВОЗМОЖНО не использовать безусловный переход....
Но ведь возможно и не пользоваться for или while... почему-то пользуются...
Я просто хочу сказать, что бывают случаи, когда goto ОЧЕНЬ УПРОЩАЕТ чтение кода....
Ну там вложенный в n-нном колене цикл из которого надо выйти.... или еще что-то....
так что говорить о вредности, неструктурированности и т.д просто неправильно...
хороша только та программа которая работает!
Ха... где-то кто-то считает что goto суть плохо.....
Если бы это было так, то такого оператора просто не существовало бы....
GOTO нужен....
и зачастую позволяет СОКРАТИТЬ и повысить УДОБОЧИТАЕМОСТЬ кода в разы....
Единственный момент -- не прыгать !!В!! функции и циклы, а из них пожалуйста...
И еще один аргумент в пользу goto:
А как вы думаете реализованы while и тому подобные циклы?
Согласен с fanto в одном. Есть случаи, когда наиболее предпочтителен goto. Всё остальное, извините, полный бред.
Goto оправдан при программировании автоматной структуры и сложных математико-физических моделей, в которых важна скорость исполнения. Структуре программы это не вредит, но скорость существенно увеличивается.
ЗЫ. Я часа 4 спорил по поводу с одним профессором (до этого тоже считал, что исключительно плохой тон). В конце спора я признал, что был не прав.
Goto оправдан при программировании автоматной структуры и сложных математико-физических моделей, в которых важна скорость исполнения. Структуре программы это не вредит, но скорость существенно увеличивается.
Автоматы можно и нужно делать без goto. Но об этом ещё можно спорить.
А по поводу скорости - полный бред!
[/COLOR]
Я в высшей математике не очень силён по этому конкретные формулы привести не могу, но суть такая.
Есть математические модели, состоящие из кучи формул, витиевато переплетающихся между собой. При следовании правилам структурного программирования реализация таких моделей неизбежно приведёт к множеству ветвлений, т.к. формулы последующих операций выбираются в зависимости от значения формулы на текущей операции.
При реализации структурными методами программирования это неизбежно приводит к тому, что рано или поздно мы оказываемся в глубине порядка 15 if’ов, из которых нужно выйти и завершить выполнение функции. Простейший if на asm’е представляет собой пару cmp/jz (это в среднем 140 тиков процессора), но простейшим он бывает редко. Помножим это число на 15. Против этого выступает jmp, который тоже в среднем выполняется за 140 тиков, но один раз! Да ещё вспомним, что эта функция используется для статистических расчётов и лежит внутри пяти-мерного цикла, и должна вычисляться в real-time. Что получается? Думаю дальше можно не считать.
Кстати сказать, Cишная функция return выполняется дольше джампа. Что выбирать – решать вам.
С автоматами та же проблема бывает. Ты (или я) с ней столкнёшься, если придётся свой компилятор делать.
Быстрее чем использовать if, break? или построенные циклы при помощи goto быстрее for, while ...? В топике обсуждался уже один реальный пример когда if+goto быстрее чем if+break - выход из вложенных циклов, при помощи goto достаточно сделать один jump, тогда как при использование if'ов требуется несколько(чтобы разбить каждый цикл по отдельности, а при помощи гото можно сразу из всех выйти). А так, что goto, if, for, break etc. - одинаково реализованы при помощи переходов. или я ошибаюсь?
Ты имеешь ввиду, что лучше не выходить из подпрограмм при помощи ретерн, который не возвращает значения? а использовать гото? Например:
{
if(x > 0) return 1;
return 0;
}
Конкретный пример, иначе, это пустая болтовня.
Есть математические модели, состоящие из кучи формул, витиевато переплетающихся между собой. При следовании правилам структурного программирования реализация таких моделей неизбежно приведёт к множеству ветвлений, т.к. формулы последующих операций выбираются в зависимости от значения формулы на текущей операции.
При реализации структурными методами программирования это неизбежно приводит к тому, что рано или поздно мы оказываемся в глубине порядка 15 if’ов, из которых нужно выйти и завершить выполнение функции.
Не поверишь, это реализунтся (если с головой) совершенно иначе.
Простейший if на asm’е представляет собой пару cmp/jz (это в среднем 140 тиков процессора), но простейшим он бывает редко. Помножим это число на 15. Против этого выступает jmp, который тоже в среднем выполняется за 140 тиков, но один раз! Да ещё вспомним, что эта функция используется для статистических расчётов и лежит внутри пяти-мерного цикла, и должна вычисляться в real-time. Что получается? Думаю дальше можно не считать.
А при чем тут вообще jmp?
Мы говорили про goto.
goto не тождество jmp
Кстати сказать, Cишная функция return выполняется дольше джампа. Что выбирать – решать вам.
А сколько выполняется "Cишная функция return" ? :D
И при чем тут "джамп"?
М-да...
Да, тут у меня прокол. Только что дизассемблировал сишный вариант, получилось mov/jmp, всё путём.
Да, быстрее. break выходит только из одного уровня {}. Т.е., если будет 15 циклов, то будет 15 брейков.
А компилятор си думает по другому:
//{
00401090 push ebp
00401091 mov ebp,esp
00401093 sub esp,40h
00401096 push ebx
00401097 push esi
00401098 push edi
00401099 lea edi,[ebp-40h]
0040109C mov ecx,10h
004010A1 mov eax,0CCCCCCCCh
004010A6 rep stos dword ptr [edi]
//goto l1;
004010A8 jmp l1+2 (004010ac)
//f();
//f();
//f();
//l1: ;
//}
Да, под школьные задачки структурное программирование хорошо ложится.
Taк я и написала об этом в своем посте, и к данному моменту никто еще не привел другого примера, когда гото лучше. Напрашивается вывод, что гото лучше, эффективней использовать для выхода из вложенных циклов. Тогда непонятно о чем тут вообще спорить можно.
http://forum.codenet.ru/showpost.php?p=164484&postcount=13
Если использовать goto там, где он не нужен - то считается криво и необходимости никакой нет. В топике был рассмотрен один реальный случай(выход из вложенных циклов), когда использование гото оправдано и не криво, другого примера вроде нет.
да ты и не должен был ее видеть, это работа автора топика. в конце концов я их объединила.
А компилятор си думает по другому:
//{
00401090 push ebp
00401091 mov ebp,esp
00401093 sub esp,40h
00401096 push ebx
00401097 push esi
00401098 push edi
00401099 lea edi,[ebp-40h]
0040109C mov ecx,10h
004010A1 mov eax,0CCCCCCCCh
004010A6 rep stos dword ptr [edi]
//goto l1;
004010A8 jmp l1+2 (004010ac)
//f();
//f();
//f();
//l1: ;
//}
Типичная ошибка уже не начинающего, но ещё неопытного программиста - ставить жесткую зависимость между командами ЯВУ и ассемблера.
Такой прямой и универсальной зависимости нет, т.к. есть множество доп. факторов.
//{
// if( f() ) {
00411A6E call f (411055h)
00411A73 movzx eax,al
00411A76 test eax,eax
00411A78 je main+2Ch (411A7Ch)
// return;
00411A7A jmp main+31h (411A81h)
// }
// f();
//}
00411A81 xor eax,eax
...
00411A96 ret
Ой! Смотри, return - это тоже jmp! :D
или вот твой же код, но скомпилированный моим компилятором:
//{
00411A50 push ebp
00411A51 mov ebp,esp
00411A53 sub esp,0C0h
00411A59 push ebx
00411A5A push esi
00411A5B push edi
00411A5C lea edi,[ebp-0C0h]
00411A62 mov ecx,30h
00411A67 mov eax,0CCCCCCCCh
00411A6C rep stos dword ptr [edi]
// goto l1;
// f();
// f();
// f();
//l1: ;
//}
00411A6E xor eax,eax
00411A70 pop edi
00411A71 pop esi
00411A72 pop ebx
00411A73 add esp,0C0h
00411A79 cmp ebp,esp
00411A7B call @ILT+935(__RTC_CheckEsp) (4113ACh)
00411A80 mov esp,ebp
00411A82 pop ebp
00411A83 ret
Вообще jmp не вижу.
Ты ещё утверждаешь, что goto это jmp и от быстрее return? :D
Извини, но тогда ты просто некомпетентен... и дальнейший спор излишен...
Можно спорить о необходимости goto, но о его быстроте по сравнению с return... :D
Да, под школьные задачки структурное программирование хорошо ложится.
Не понял фразы, растолкуй.
http://forum.codenet.ru/showpost.php?p=164484&postcount=13
Можно спорить о том, что само по себе большое количество вложенных циклов, да ещё и в одной функции - это зло.
Если к этому злу добавить goto, то это зло становиться ещё и трудночитаемым и полохо поддающимся рефакторингу.
Согласись, что спасательная шлюпка - не лучший способ пересекать Атлантику. Если к тебя 15 (!) вложенных циклов , да еще и с таким жутким условием выхода, то может просто надо подумать над реализацией всего алгоритма, а не о том, что лучше использовать goto?
{
if(!Init1(&pData1))
{
printf("Не проиден первый шаг инициализации.\n");
goto shutdown;
}
if(!Init2(&pData2_0, &pData2_1))
{
printf("Не проиден второй шаг инициализации.\n");
goto shutdown;
}
// ...
// Выходим без ошибки.
return 1;
shutdown:
// Финализируем и выходим с ошибкой.
Shutdown();
return 0;
}
void Shutodown()
{
if(pData1)
{
free(pData1);
pData1 = NULL;
}
if(pData2_0)
{
free(pData2_0);
pData2_0 = NULL;
}
if(pData2_1)
{
free(pData2_1);
pData2_1 = NULL;
}
// ...
}
По-моему, подход с goto компактнее, намного легче читаем и более стабилен нежели ручная финализация и возвращение после неудачи.
Да тот код, который ты привел - это жуть.
Его можно сделать намного аккуратнее и уж тем более без goto. Обычно такие вещи обычно делаются с помощью цикла иннициализации. Я уже как-то рассказывал об этом на форуме.
Вопрос производительности?!
Может ты объяснишь, как goto влияет на производительность?
Да тот код, который ты привел - это жуть.
Его можно сделать намного аккуратнее и уж тем более без goto. Обычно такие вещи обычно делаются с помощью цикла иннициализации. Я уже как-то рассказывал об этом на форуме.
Код, пожалуйста, особено для ситуации, когда в функции передаются разные параметры в различных последовательностях. И обоснование, почему он читабельнее и аккуратнее. Иначе, буду расценивать, как пустую болтовню.
Вопрос производительности?!
Может ты объяснишь, как goto влияет на производительность?
Легко. Что быстрее переход на определнный адрес (goto) или засовывание параметров в стек, переход на определенный адрес и возвращение (вызов функции)?
И еще, вы сами синтаксический анализатор писали, чтобы так говорить? Очевидно, вы плохо знакомы с системным программировнием.
*уселся в первом ряду с пивом и чипсами*
И так, приступим...
Глава 1, в которой рассказывается, что goto является симптомом плохой структурированности программы.
Ответь, для чего твоя функция Init() ? А что она делает?
Отвечу на вопрос, т.к. вижу это я, читатель твоего кода.
Эта функция для того, чтобы что-то иницивлизировать. А делает она следущее: инициализирует последовательно какие-то подсистемы, обрабатывает ошибки инициализации, выводит информацию об ошибках, вызывает деинициализацию. Странно, что ко всему этому она не варит кофе и не пылесосит.
Налицо ошибка структурирования: функция должна по возможности выполнять что-то одно и соотв-но называться.
Поэтому твоя функция - это на самом деле три зверя в одной шкуре:
1) инициализатор,
2) обработчик ошибок,
3) вывод инф.
В зависимости от конкретики выглядеть они будут по-разному, но сути это не меняет.
Возьмем простейший пример с твоим кодом:
{
int error = Init();
if (error != ERROR_OK) {
// Финализируем и выходим с ошибкой.
Shutdown();
errorTextOutput(int error);
return 0;
}
// Выходим без ошибки.
return 1;
}
int Init()
{
if ( !Init1(&pData1) )
return ERROR_INIT1
if(!Init2(&pData2_0, &pData2_1))
return ERROR_INIT2
// ...
// Выходим без ошибки.
return ERROR_OK;
}
void errorTextOutput(int error)
{
printf( errorMsg[error] );
}
Объяснять про читабельность или сам видишь?
Глава 2, в которой сказано, как лучше ЭТО делать.
Как уже говорил, для инициализации подобного рода, когда есть множество последовательных и критичных инициализаций подсистем, используется пошаговая инициализация/деинициализация. Её использование делает инициализацию и обработку ошибок более гибкими и аккуратными. Так у тебя функуция Shutodown() очень сомнительна, т.к. деинициализация происходит не в обратной последовательности относительно инициализации, а что деинициализировать выясняется по косвеному признаку - "то что не ноль", а если надо деинициадизировать, даже если ноль?
Я уже описывал схему такой пошаговой инициализации/деинициализации. Поищи на форуме.
Легко. Что быстрее переход на определнный адрес (goto) или засовывание параметров в стек, переход на определенный адрес и возвращение (вызов функции)?
Во первых, для невнимательных, я ещё раз повторяю:
return - это не ret,
goto - это не jmp,
вызов функции - это не call.
Очевидно, вы плохо знакомы с программировнием на языках программирования. :D
Во вторых, преждевременная оптимизация - корень всех бед, а то что как ты её пытаешься представить здесь, вообще назвать оптимизацией трудно.
Во-первых, зачем вводить лишние функции и константы, когда можно ввести одну метку? К тому же при добавлении нового этапа, придется добавлять строку в таблицу строк, создавать новую константу, т.е. прыгать по коду. Чтобы даже чуть-чуть изменить сообщение об ошибке, нужно будет взять номер ошибки и вруную считать строки в таблице, чтобы найти нужную строчку. Это все факторы, облегчающие рефакторинг?
Во-вторых, я могу выводить в сообщениях об ошибках какие-то параметры, относящиеся к данному этапу инициализации, что в вашем методе затруднительно.
Далее...
Если вы думаете, что goto реализуется не через jmp, а вызов и возвращение из функции - не через call и ret, то читаем доку по ассемблеру и смотрим как компиляторы генерируют код.
Насчет оптимизации...
Взгляните на вывод генераторов flex и bison и посчитайте количество goto. Они там введены не от хорошей жизни. Это единтсвенный достаточно эффективный и быстрый способ огранизовать сложное ветвление.
Другое дело, что такие задачи - редкость, но говорить, что goto совсем не нужен - в корне не верно.
Во-первых, зачем вводить лишние функции и константы, когда можно ввести одну метку?
А зачем, вообще, писать на ЯВУ ?
А ответ на твой вопрос в начале моего предыдущего поста. Читал?
К тому же при добавлении нового этапа, придется добавлять строку в таблицу строк, создавать новую константу, т.е. прыгать по коду.
Ну строку придется добавлять все равно, не так ли?
Константу можно не создавать, это всего лишь пример реализации и "а если" можно придумать сколько угодно. Возвращай строку, а не номер ошибки, но это уже будет некрасиво.
Чтобы даже чуть-чуть изменить сообщение об ошибке, нужно будет взять номер ошибки и вруную считать строки в таблице, чтобы найти нужную строчку.
:D
М-да...
А давать нормальные, значимые, имена не пробовал?
И с чего ты взял, что надо что-то считать в таблице?
В конце концов, я привел лишь пример соотв. кода ошибки и его сообщения.
Кроме того, это уже вопрос не по goto, а по организации хранения текстовых сообщений. Так вот весь output должен быть отвязан от бизнес-логики. Хочешь с этим поспорить?
Это все факторы, облегчающие рефакторинг?
Да, разгранечение прав и ответственности - методы облегчающие как рефакторинг, так и развитие кода.
Во-вторых, я могу выводить в сообщениях об ошибках какие-то параметры, относящиеся к данному этапу инициализации, что в вашем методе затруднительно.
А я могу выводить сообщения на 30 языках мира, что в твоем коде вообще не возможно.
Я ещё раз повторяю: весь output должен быть отвязан от бизнес-логики и это уже вопрос не по goto.
Я могу придумать и генерацию сообщений на основании конкретной инф. ао аремя инициализации. И поверь, эта генерация не будет зашита в код бизнес-логики.
Далее...
Если вы думаете, что goto реализуется не через jmp, а вызов и возвращение из функции - не через call и ret, то читаем доку по ассемблеру и смотрим как компиляторы генерируют код.
Ну так посмотри! Несколькими постами выше.
Тебе перечислить некоторые варианты, когда вызов функции - это не call, return - это не ret, а goto - это не jmp, или сам попытаешься?
Насчет оптимизации...
Взгляните на вывод генераторов flex и bison и посчитайте количество goto. Они там введены не от хорошей жизни. Это единтсвенный достаточно эффективный и быстрый способ огранизовать сложное ветвление.
1) при чем тут оптимизация?
2) уто сказал, что единстыкнный?
3) кто сказал, что эффективный?
4) а зачем организовывать таким образом "сложное ветвление"?
Другое дело, что такие задачи - редкость, но говорить, что goto совсем не нужен - в корне не верно.
Давай так. Я не знаю не одной практической задачи, в которой goto был бы необходим. Даже больше, для меня наличие goto - признак того, что код умирает и начинает разлашаться и сл-но есть необходимость либо рефакторинга, либо вообще пересмотра архитектуры.
Кроме того, это уже вопрос не по goto, а по организации хранения текстовых сообщений. Так вот весь output должен быть отвязан от бизнес-логики. Хочешь с этим поспорить?
...
А я могу выводить сообщения на 30 языках мира, что в твоем коде вообще не возможно.
Про разделение спорить не буду и мой пример это разделение не отрицает, можно даже сделать это разделение болеее прозрачным. К тому же я тоже могу начать свой пример развивать. Его можно интернациаонализировать и т.д. Я привел лишь пример, в пользу того, что goto не ухудшает читабельности кода.
Наш диалог превращается в анализ моего кода с точки зрения парадигмы, что goto - зло. Goto - зло, когда им злоупотребляют. Я пытаюсь показать, что goto читабельность не ухудшает. Почувствуйте разницу.
Ну так посмотри! Несколькими постами выше.
Тебе перечислить некоторые варианты, когда вызов функции - это не call, return - это не ret, а goto - это не jmp, или сам попытаешься?
Ситуацию представить не сложно. Например inline функции. Возможно некоторые компиляторы могут проводить дополнительные оптимизации, при вызове функций.
Но при вызове обычной функции обязательно выполниться как минимум один call и один ret.
1) при чем тут оптимизация?
2) уто сказал, что единстыкнный?
3) кто сказал, что эффективный?
4) а зачем организовывать таким образом "сложное ветвление"?
Предложте более элегантное решение. Популязировать чужие парадигмы и я могу, а что толку?
Давай так. Я не знаю не одной практической задачи, в которой goto был бы необходим. Даже больше, для меня наличие goto - признак того, что код умирает и начинает разлашаться и сл-но есть необходимость либо рефакторинга, либо вообще пересмотра архитектуры.
Я вам привел одну задачу, где оно оправдано. Вы с ней знакомы?
Если использовать goto там, где он не нужен - то считается криво и необходимости никакой нет.
[/quote]
Согласн
[quote=Green]
Ты ещё утверждаешь, что goto это jmp и от быстрее return?
[/quote]
По поводу return'а я уже признал свою ошибку. По поводу goto/jmp, ты скорее всего используешь оптимизирующий компилятор, естественно он вырезает функции, которые вообще нигде не вызываются. В реальных задачах (когда обе ветки управление получают) goto - это jmp.
Пример конкретный привести не мог, т.к. с задачей не сталкивался, когда goto предпочтителен. Спасибо Nixus, одну из таких привёл.
А я, пожалуй, присоеденюсь к squirl-у. Надеюсь он чипсами поделится. ;) Пиво своё.
for(int j=0;j<n2;++j) {
if(come_condition1) goto next1;
for(int k=0;k<n3;++k) {
if(come_condition2) goto next2;
}
// some code
}
next2:
// some code
}
next1:
// some code
Обработка ошибок с использованием GOTO
// Open a file and assign it a control object.
// Returns the control object on success, or NULL on failure.
struct Control * open_control(const char *fname)
{
struct Control * ctl = NULL;
FILE * fp = NULL;
// 1. Allocate a control object
ctl = malloc(sizeof(struct Control));
memset(ctl, 0, sizeof(struct Control));
if (ctl == NULL) // E-1
goto fail;
// 2. Save the file name
ctl->name = malloc(strlen(fname)+1);
if (ctl->name == NULL) // E-2
goto fail;
strcpy(ctl->name, fname);
// 3. Open the named file
fp = fopen(fname, "rb");
if (fp == NULL) // E-3
goto fail;
ctl->fp = fp;
// 4. Read the file header block
if (!read_header(ctl)) // E-4
goto fail;
// Return success
return ctl;
fail:
// Failure occurred, clean up allocated resources
if (ctl != NULL)
{
if (ctl->fp != NULL)
fclose(ctl->fp); // H-3
if (ctl->name != NULL)
free(ctl->name); // H-2
free(ctl); // H-1
}
// Return failure
return NULL;
}
Без использования GOTO
// Open a file and assign it a control object.
// Returns the control object on success, or NULL on failure.
struct Control * open_control(const char *fname)
{
struct Control * ctl = NULL;
FILE * fp = NULL;
int err = 0;
// 1. Allocate a control object
ctl = malloc(sizeof(struct Control));
memset(ctl, 0, sizeof(struct Control));
if (ctl == NULL) // E-1
err = 1;
// 2. Save the file name
if (err == 0)
{
ctl->name = malloc(strlen(fname)+1);
if (ctl->name == NULL) // E-2
err = 2;
else
strcpy(ctl->name, fname);
}
// 3. Open the named file
if (err == 0)
{
fp = fopen(fname, "rb");
if (fp == NULL) // E-3
err = 3;
else
ctl->fp = fp;
}
// 4. Read the file header block
if (err == 0)
{
if (!read_header(ctl)) // E-4
err = 4;
}
// Check for success
if (err == 0)
return ctl;
// Failure, clean up
if (err > 3)
fclose(ctl->fp); // H-3
if (err > 2)
free(ctl->name); // H-2
if (err > 1)
free(ctl); // H-1
return NULL;
}
Что скажете, мистер Green? Так что приношу самому себе же свои глубочайшие извинения. Я всё-таки был прав.
Хотя вот ещё интересный вариант, но тоже спорный.
SEH
{
try
{
dest.acquire();
dest.write(data[0]);
dest.write(data[1]);
dest.write(data[2]);
}
catch (ResourceException ex)
{
// Failure occurred, clean up
log.error(ex);
dest.reset();
}
finally
{
// Always executed
dest.release();
}
}
Кстати, у нас в следующем году юбилей. 50 лет люди грызутся по поводу GOTO. Без балды. Побухаем...
"Выход из множества вложенных циклов одновременно"
Ни разу не умерщвляется. Поместить циклы в процедуру/функцию и выйти из неё по условию.
Не далее как в январе написал приятельнице КА без единого Goto, паче того, не выходя за рамки стандартного Паскаля.
Вообще странный спор. В Java слово goto зарезервировано, но ничего не делает. Для C# в MSDN приводится красивый пример того, как делать не надо:
using System;
class SwitchTest
{
static void Main()
{
Console.WriteLine("Coffee sizes: 1=Small 2=Medium 3=Large");
Console.Write("Please enter your selection: ");
string s = Console.ReadLine();
int n = int.Parse(s);
int cost = 0;
switch (n)
{
case 1:
cost += 25;
break;
case 2:
cost += 25;
goto case 1;
case 3:
cost += 50;
goto case 1;
default:
Console.WriteLine("Invalid selection.");
break;
}
if (cost != 0)
{
Console.WriteLine("Please insert {0} cents.", cost);
}
Console.WriteLine("Thank you for your business.");
}
}
А к вопросу о вложенных циклах вот навскидку пример, правда, на VB.NET.
For[/COLOR] i [COLOR="Blue"]As Integer[/COLOR] = 0 [COLOR="Blue"]To[/COLOR] 100
[COLOR="Blue"]For[/COLOR] j [COLOR="Blue"]As Integer[/COLOR] = 0 [COLOR="Blue"]To[/COLOR] 100
[COLOR="Blue"]For[/COLOR] k [COLOR="Blue"]As Integer[/COLOR] = 0 [COLOR="Blue"]To[/COLOR] 100
[COLOR="Blue"]For[/COLOR] l [COLOR="Blue"]As Integer[/COLOR] = 0 [COLOR="Blue"]To[/COLOR] 100
[COLOR="DarkGreen"]'...[/COLOR]
[COLOR="Blue"]For[/COLOR] z As Integer = 0 [COLOR="Blue"]To[/COLOR] 100
[COLOR="Blue"]If[/COLOR] var = ParameterArray(i, j, k, l, m, n, o, p, r, s, t, u, v, w, x, y, z) [COLOR="Blue"]Then
Return[/COLOR] var
[COLOR="Blue"]Exit Function[/COLOR]
[COLOR="Blue"]End If
Next[/COLOR]
[COLOR="DarkGreen"]'...[/COLOR]
[COLOR="Blue"]Next
Next
Next
Next
End Function[/COLOR]
Я не сказал, что написать без goto КА нельзя. Вопрос в том насколько использование и не использование goto повлияет на размер кода, читабельность и производительность.
По поводу циклов по-моему уже давно проехали.
Кстати, одна из причин по которой мне не нравится та же Java - так это то, что они выкинули очень мощные, но естественно опасные инструменты. Это потакание глупости и скорее регресс, чем прогресс.
(с) amirul
Существует два правила, когда goto практически не нарушает читабельность кода
1. Переходить можно только вперед
2. Заходить в блоки категорически нельзя (либо оставаться либо выходить)
Неиспользование goto даже там где это оправдано - это что то типа религии. Лучше не спорь с религиозными людьми - все равно ничего им не докажешь.
(c) Serg
Вдумчиво смотрим disassembly, любезно опубликованную тов. Green 30.07.2007 в 06:57. После вдумчивого разглядывания кода расскажите мне, где и как goto влияет на производительность? Сказано же: goto <> jmp. Ясно, что при написании кода на ЯВУ нельзя заранее предсказать, как он будет отображён в машинные коды. Если же речь идёт о таких вещах, как Java или .Net, то тут вообще невозможно определить результат отображения. Как в этом случае можно рассуждать о производительности?
Замечено, что создание экземпляра класса занимает времени в десятки раз большее, чем выход из цикла или условия. Ок, допустим, что в Паскале мы не создаём экземпляры классов. Но множество вложенных циклов – это чем можно оправдать? Что вы делаете такими конструкциями? В самом деле, обход десятимерного массива может показаться удобным делать при помощи десяти вложенных циклов, но вот вопрос: как это отлаживать? А если массив трёхсотмерный? Или вообще динамический? Что тогда?
Если в циклах мы выполняем не одно-два сравнения, а пять-шесть процедур, тогда неэффективной ставновится сама идея циклов. Отсюда и мысль о том, что вложенные в большом количестве циклы говорят о плохом проектировании.
К вопросу о читабельности я привёл пример из MSDN на C#. Вроде бы всё понятно, и читается легко. Однако легко ли навскидку сказать, сколько будет стоить кофе в случае 3? В этом примере несложно, поскольку лёгкий пример. Теперь допустим, что вместо += 25 у нас везде стоит [FONT="Courier New"]= sin(tan(cost))[/FONT]. Или вообще что-то вроде new [FONT="Courier New"]CashMachineEmulator[/FONT]. Вы видите здесь оптимизацию? Я вижу здесь ресурсоёмкую операцию. Да, пример сам по себе не показательный, но хорошая практика состоит в том, чтобы заранее избегать потенциально плохих конструкций. Принципиально возможно вовсе обойтись без Goto. Вот, что говорит классик.[QUOTE=Niklaus Wirth]As a corollary, a language must allow, encourage, or even enforce formulation of programs as properly nested structures, in which properties of the whole can be derived from properties of the parts. Consider, for example, the specification of a repetition R of a statement S. It follows that S appears as a part of R. We show two possible forms:
R0: while b do S end R1:
repeat S until b
The key behind proper nesting is that known properties of S can be used to derive properties of R. For example, given that a condition (assertion) P is left valid (invariant) under execution of S, we conclude that P is also left invariant when execution of S is repeated. This is formally expressed by Hoare’s rules
{P & b} S {P} implies {P} R0 {P & ¬b}
{P} S {P} implies {P} R1 {P & b}
[COLOR="DarkRed"]If, however, S contains a go to statement, no such assertion is possible about S, and therefore neither any deduction about the effect of R. This is a great loss. Practice has indeed shown that large programs without go to are much easier to understand, and that it is very much easier to give any guarantees about their properties.[/COLOR][/QUOTE]Выделение цветом моё.
Ну чтож вы уперлись в автоматы со своим goto. Все это вполне качественно, и что самое главное легко читаемо и поддерживаеммо, решается без него. Для чего придумывали языки высокого уровня, для чего существуют современные парадигмы программирования, которыми вы вроде и пытаетесь пользоваться, а потом тут же нарушаете. Ну вы же не в машинных кодах пишете в конце концов и не на ассеблере. Зачем пытаться ассоциировать код с ассемблерными командами (когда языки высокого уровня сремятся быть как можно абстрагированней от аппаратной платформы и т.п.). Ну не нужна эта преждевременная оптимизация - она только заранее всю структуру программы испортит, послушайте Кнута (да и Green тоже упоминал), он умный дядька и опыта у него куда побольше вашего. =))
Такое ощущение, что не приходилось сталкиваться с какой то более менее объемной задачей, а потом разруливать последствия вот такого вот стиля программирования.
Кстати, одна из причин по которой мне не нравится та же Java - так это то, что они выкинули очень мощные, но естественно опасные инструменты. Это потакание глупости и скорее регресс, чем прогресс.
(с) amirul
Цитата:
Существует два правила, когда goto практически не нарушает читабельность кода
1. Переходить можно только вперед
2. Заходить в блоки категорически нельзя (либо оставаться либо выходить)
Неиспользование goto даже там где это оправдано - это что то типа религии. Лучше не спорь с религиозными людьми - все равно ничего им не докажешь.
(c) Serg
Ну и что эти цитаты дают? ну лишний повод упереться. =)
Вот в ответ тоже цитата:
http://khpi-iip.mipk.kharkiv.edu/library/extent/dijkstra/pp/ewd215.html
Дейкстра к слову куда более авторитетный и уважаемый в программистской среде человек.
Виноват, что и быстрее чего? Быстрее написать, быстрее отладить?
А как нужно? Ну, хотя бы так:
using System;
class SwitchTest
{
static void Main()
{
Console.WriteLine("Coffee sizes: 1=Small 2=Medium 3=Large");
Console.Write("Please enter your selection: ");
string s = Console.ReadLine();
int n = int.Parse(s);
int cost = 25;
switch (n)
{
case 1:
break;
case 2:
cost += 50;
break;
case 3:
cost += 75;
break;
default:
Console.WriteLine("Invalid selection.");
break;
}
if (cost != 0)
{
Console.WriteLine("Please insert {0} cents.", cost);
}
Console.WriteLine("Thank you for your business.");
}
}
А если еще код или часть кода пишется исходя из того что он будет работать на разных аппаратных платформах (а большинство ЯВУ это позволяют), то о каком вобще отображении кода на ассемблер конкретного железа может идти речь? )