LINUX.ORG.RU

do{} while(0) вместо вложенных ифов

 ,


2

4

Привет!
Народ, откуда пошла такая конструкция?

do
{
 if ( !cond0 ) break;
 foo();
 if ( !cond1) break;
 bar();
 //...
 if ( !condN) break;
return true;
} while ( 0 )
return false;


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


Обычно вместо break используют return и, соотвественно, функции

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

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

Меньше догматизма.

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

но с гоуту, к счастью, ни разу встреч не было

Далеко не факт, что к счастью. Иногда goto добавляет читаемости коду.

i-rinat ★★★★★
()

Антиgoto-шник какой-то писал. Ну или это: «всегда должна быть одна точка выхода»(тут правда нифига не одна, но за то практически рядом)

Deleted
()

Это удобно использовать при генерации кода, т.к упираешься в ограничение компиляторов на количество case в switch (что-то около пары тыщь встречал).

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)

От отсутствия или нежелания пользоваться goto

AlexAT
()

Можно ещё желчь поизливаю. Вот так видишь блин творение безготошников. Что на сях, что на пыхе. И видишь мля свитч-фор-иф уровня так 8 вложенности. И вдруг break. Сцуко!!! Гото для кого придумали?!

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

Ну, стоит заметить, что goto не очищает скоуп, и можно например не создавать (пусть даже и на стеке), то, что создавать ненужно. Пока моя гипотеза, что это способ сэкономить на вызове функции, имея почти все преимущества от оного(окромя читебельности).

Вообще, я как-то с человеком собаку съевшим на такой экономии спорил, что

std::numeric_limits<double>::max();

раскроется в константу в любом адекватном компиле в релизе. Другое, дело, что есть неадекватные компили и есть вещи которые могут соптимизироваться а могут и нет.

pon4ik ★★★★★
()

Охренеть как элегантно: запихнуть управляющую конструкцию для цикла туда, где его нет и не подразумевается. Читаемость повышается просто несказанно.

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

И вдруг break

Пихпих:

foreach (...) {
    foreach (...) {
        // да, брякаем второй с этого уровня форич
        // так же можно и с continue
        if (...) break 2;
    }
}

deep-purple ★★★★★
()
Ответ на: комментарий от pon4ik

goto не очищает скоуп

Заинтриговал, если честно. Можно подробнее? Я пока по быстрому глянул:

If transfer of control exits the scope of any automatic variables (e.g. by jumping backwards to a point before the declarations of such variables or by jumping forward out of a compound statement where the variables are scoped), the destructors are called for all variables whose scope was exited, in the order opposite to the order of their construction

Или не это имелось ввиду?

std::numeric_limits<T>::max()

Кстати, вызов не всегда актуален:

Meaningful for all specializations in which is_bounded != false

Deleted
()
Ответ на: комментарий от pon4ik
std::numeric_limits<double>::max();

раскроется в константу в любом адекватном компиле в релизе. Другое, дело, что есть неадекватные компили и есть вещи которые могут соптимизироваться а могут и нет.

Что тут спорить?

Оно и в дебаге будет константа. Потому как constexpr

https://en.cppreference.com/w/cpp/types/numeric_limits/max

static constexpr T max(); (since C++11)	
fsb4000 ★★★★★
()
Ответ на: комментарий от Deleted

Фига, я реально не знал, что goto очищает скоуп! Пребывал в святой уверенности, что оно транслируется в jmp или что-то в духе, век живи век учись :) Тогда, действительно непонятно, почему так много ненависти вокруг этого оператора.

Про лимиты, речь шла про конкретный тип, это был или double или size_t, уже не вспомню.

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

Я почти уверен, что constexpr как явление, появился через n лет после этого спора.

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

goto вниз, для выхода из блока - вполне оправдан

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

А вот за гото вверх

В Linux есть. Но в таких местах, где без него — жуть и мрак. Там и с goto жуть и мрак, но хотя бы терпимые.

или кроссблок

А что, так можно было?

i-rinat ★★★★★
()
Ответ на: комментарий от AlexAT

Это ты ещё break;break;break; не видел. Ладно бы там break;break;continue;. А всё почему? Всё потому, что в языке нет goto и switch.

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

Гото для кого придумали?!

И ты правда думаешь, что goto из восьмого уровня вложенности сделает код понятнее?

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

или кроссблок

А что, так можно было?

При собдюдении некоторых условий, вроде можно:

If transfer of control enters the scope of any automatic variables (e.g. by jumping forward over a declaration statement), the program is ill-formed (cannot be compiled), unless all variables whose scope is entered have
1) scalar types declared without initializers
2) class types with trivial default constructors and trivial destructors declared without initializers
3) cv-qualified versions of one of the above
4) arrays of one of the above

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

Ну или это: «всегда должна быть одна точка выхода»(тут правда нифига не одна, но за то практически рядом)

Под «одна точка выхода» подразумевается совсем другое. А именно, что не должно быть так:

...
goto subroutine;
label1: ...
...
goto subroutine;
label2: ...
...
mars: ...
...
subroutine:
...
if (cond1) goto label2;
...
if (cond2) goto label1;
...
goto mars;
Т.е. выход из подпрограммы возможен не в ту точку откуда она была вызвана. В процедурных языках такое попросту невозможно, точка выхода всегда одна - то место откуда вызвали процедуру/функцию. (Без всяких longjmp и т.п. конечно).

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Под «одна точка выхода» подразумевается совсем другое

Смотря кем. Я имел ввиду один return на функцию. Срачей по поводу возврата в несколько точек пока не слышал(видимо, не сильно популярно)

Deleted
()

На самом деле такой конструкции не хватает в реальности. Например проверить ряд взаимоисключающих условий. В case-то выражения не засунешь!

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

Ага, кейз с условием. Что не нравится, не совсем понятно. Да и вообще, в определенном контексте вполне логично.

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

Все, я не до конца понял код сам. Там не смотря на foo и bar возвращается true.

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

Речь была про std::numeric_limits<double>::max(). Наверное, мне не следовало употреблять слово «сабж»(в моём посте он имеет «локальный» смысл)

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

Оно и в дебаге будет константа. Потому как constexpr

Да оно и до C++11 было константой в смысле что не менялось от вызова к вызову.

Вопрос был про

раскроется в константу

«Раскроется» это видимо надо понимать как «не будет вызова функции».

В дебаге есть вызов функции даже с constexpr.

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

Там в основном определения.

Конкретно цитату покажи, которая гарантирует. А то эксперимент показал, что в дебаге остаётся вызов constexpr-функции numeric_limits<double>::max(). Я, конечно, не исключаю бага компилятора, но это кажется мне маловероятным.

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

Constant expressions can be evaluated during translation

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:
...
— an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor (12.4)
...
— an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
—— it is initialized with a constant expression or
—— it is a non-static data member of an object whose lifetime began within the evaluation of e;

Как-то так. Хотя гарантий тут нет. Но может я не нашёл

Deleted
()

Обычно встречается в макросах из-за точки с запятой.

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

проверить ряд взаимоисключающих условий. В case

А как-то так не получится?

switch  ((..(( 
  условие0  <<1|| 
  условие1 )<<1|| 
  условие2 )<<1|| 
  ...
  условиеN ) {
case 1<<(N-0): ... break;
case 1<<(N-1): ... break;
...
case 1<<(N-N): ... break;
}
DonkeyHot ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.