LINUX.ORG.RU

Противникам goto: обработка ошибок


0

0

Пишу функцию, которая постепенно считывает нечто из файла в память.

Сейчас код пестрит конструкциями вида:

if (что-то плохое) { free(array); return NULL; }

не логичнее было бы писать

if (что-то плохое) goto err;

а в конце:

err: free(array); return NULL;

Вопрос обращён к противникам использования оператора goto в языке C.

★★★★

Ответ на: комментарий от Kpoxman

"не логичнее ли было бы писать".. :)

Просто есть некая теория, что использовать goto - абсолютное зло. Мне хочется поинтересоваться у людей, разделяющих эту точку зрения, как, по их мнению, надо вести себя в подобной ситуации.

P.S. за форматирование прощу прощения. думаю, что такой простой код всё равно не сложно понять.

Davidov ★★★★
() автор топика

Не являюсь противником goto (хоть сам его никогда не использую), 
но я бы вынес весь код, где может случится что то плохое, 
в отдельную функцию, ей бы передавал array параметром, и в ней писал

if (что-то плохое)
    return NULL;

а в главной функции 

if (NULL == my_func(array)) {
    return NULL;
    free(array);
}

Вообще декомпозиция помогает решать много проблем.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

>Вообще декомпозиция помогает решать много проблем.

Отличное решение. Спасибо.

Davidov ★★★★
() автор топика

Классики пишут:

-----------
Однако существуют случаи, в которых goto может пригодиться. Наиболее 
типична ситуация, когда нужно прервать обработку в некоторой глубоко 
вложенной структуре и выйти сразу из двух или большего числа вложенных 
циклов. Инструкция break здесь не поможет, так как она обеспечит выход 
только из самого внутреннего цикла. В качестве примера рассмотрим 
следующую конструкцию:

for (...)
    for (...) {
        ...
        if (disaster) /* если бедствие */
            goto error; /* уйти на ошибку */
error: /* обработка ошибки */
    ликвидировать беспорядок

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

Поэтому использовать goto в твоем случае нормально.

shumer
()
Ответ на: комментарий от Davidov

> Просто есть некая теория, что использовать goto - абсолютное зло.

эта теория реально относится к нелокальным goto -- грубо говоря когда у тебя программа на N тысяч строк, не разбитая на функции, и goto перебрасывает из одного конца этого дерьма в другой. В случае C аналогия этому: longjmp.

Люди, применяющие эту теорию к обычному goto в пределах 30-строчной функции на С: эти люди просто неадекватны

dilmah ★★★★★
()

Сделайте поиск скажем в дир-ии /drivers в ядре - увидите много (ну очень много) примеров использования goto. Если мне память не изменяет - там где-то должно быть описание что в некоторых случаях goto позволяет сгенерировать более эффективный код.

Mr_Nobody
()
Ответ на: комментарий от Davidov

> Просто есть некая теория, что использовать goto - абсолютное зло. Мне хочется поинтересоваться у людей, разделяющих эту точку зрения, как, по их мнению, надо вести себя в подобной ситуации.

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

Burbaka ★★
()
Ответ на: комментарий от Legioner

if (NULL == my_func(array)) {
return NULL;
free(array);
}

наверное, сначала освободим память, потом вернем null :)

anonymous
()
Ответ на: комментарий от anonymous

Очень интересная статья, спасибо.

>Я не заявляю, что упомянутые предложения являются исчерпывающими в том смысле, что они удовлетворяют любым требованиям, но какие бы предложения не приводились (например, предложение прекращения), они должны удовлетворять тому требованию, чтобы при них могла бы поддерживаться независимая от программиста система координат для описания процесса полезным и осуществимым способом.

Если я правильно понимаю, то конструкция вида

int func(...) {

...

if (bad) goto exit;

...

exit:

...

}

не противоречит создания независимой от программиста системы координат. Так что даже Дейкстра был бы доволен :)

Всем огромное спасибо за полезные комментарии.

Davidov ★★★★
() автор топика

grep -r goto /usr/src/linux

Думаю, всё понятно. Я юзаю goto! (надо будет на аватарке написать :))

Zmacs
()

от криворукие собрались.. нет чтобы подумать как по нормальному написать, хотя бы так:
do
{
   if( something bad ) { break; }
   ...
   done = true;
} while( false );
if( !done )
{
   free( array );
   value = NULL; 
}
return value;

anonymous
()
Ответ на: комментарий от shumer

За что я люблю Фортран 90 и выше -- там можно циклы именовать, типа

cycle: do i=1,n

enddo

и внутри делать выход по break cycle -- из любого вложенного :)

gene
()
Ответ на: комментарий от gene

фортран опопсел.. они из последнего стандарта выкинули assigned goto..

dilmah ★★★★★
()
Ответ на: комментарий от anonymous

>от криворукие собрались.. нет чтобы подумать как по нормальному написать, хотя бы так:...

>>Упражнения по более или менее механическому переводу произвольной схемы алгоритма в схему без переходов, однако, не рекомендуются. При этом не ожидается, что результирующая схема будет более понятной, чем исходная.

anonymous
()
Ответ на: комментарий от gene

В перле тоже можно.

Там еще можно делать next LABEL (ну, то есть на C это называется continue).

А по топику - использовать if (error) goto cleanup_and_exit - нормально вполне, пол-ядра (как уже говорили) так написано. Только функция должна быть при этом по возможности небольшая, чтобы (в идеале) переход и его адрес помещались на экране одновременно.

anonymous
()

Вообще говоря, goto это аналог ассемблерного jmp, если говорить с точки зрения ассемблера, то ,например, циклы и условные переходы в случае else реализуются с помощью jmp, и без jmp там никак. В Сях же для циклов и условных переходов есть свои операторы, которые при компиляции так или иначе задействуют jmp. Это я к тому, что goto это не зло, а очень полезная штука. Для выхода из нескольких вложенных циклов или условий или для обработки различных ошибок перед выходом из функции, очень удобно использовать goto, да и код получается оптимальнее. Согласен с dilmah *** (*) (29.01.2007 14:50:47), использование goto в неструктурированном коде приводит к бардаку. Итого, goto использовать можно, и даже в некоторых случаях нужно, главное без фанатизма :)

anonymous
()

В документации к avahi в примерах тоже используется goto абсолютно в таком же контексте: http://avahi.org/download/doxygen/client-browse-services_8c-example.html . Ничего страшного, лишь бы код читался, а с goto он читабельней, чем кто-то здесь предлагал do {} while ();

Bohtvaroh ★★★★
()

я как сторонник c++ вообще не понимаю необходимости чистить память руками - деструкторы наше всйо!

anonymous
()
Ответ на: комментарий от anonymous

> я как сторонник c++ вообще не понимаю необходимости чистить память руками - деструкторы наше всйо!

Сторонник, ты бы начала выучил плюсы. Или delete уже отменили?

Bohtvaroh ★★★★
()
Ответ на: комментарий от Bohtvaroh

Умные указатели это что-то типа boost::shared_ptr<>, boost::intrusive_ptr<>, boost::scoped_ptr<> и т.д. в зависимости от контекста. При их использовании количество delete в коде находится на уровне статистической погрешности.

syomin
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.