Я смотрел код человека и заметил, что у него, похоже, есть шаблон в своих функциях:
<return-type> function(<params>)
{
<initialization>
do
{
<main code for function>
}
while(false);
<tidy-up & return>
}
Это неплохо , более своеобразно (реальный код довольно аккуратный и неудивительный). Это не то, что я видел раньше, и мне было интересно, может ли кто-нибудь придумать какую-либо логику, стоящую за этим - возможно, фон на другом языке?
do...while()
и с тех пор он использовал этот код в качестве шаблона функции.Ответы:
Вы можете
break
выйти изdo{...}while(false)
.источник
Многие люди отмечают, что это часто используется с break как неудобным способом написания «goto». Вероятно, это правда, если это написано прямо в функции.
В макросе OTOH
do { something; } while (false)
- это удобный способ ПРИНУДИТЕЛЬНО поставить точку с запятой после вызова макроса, за которым не может следовать никакой другой токен.И еще одна возможность состоит в том, что либо там когда-то был цикл, либо ожидается добавление итерации в будущем (например, при разработке, управляемой тестами, итерация не требуется для прохождения тестов, но логически имеет смысл зацикливаться там, если функция должна была быть несколько более общей, чем требуется в настоящее время)
источник
Разрыв как goto, вероятно, является ответом, но я предложу еще одну идею.
Возможно, он хотел иметь локально определенные переменные и использовал эту конструкцию для получения новой области видимости.
Помните, что хотя последний C ++ позволяет
{...}
делать что угодно, это было не всегда.источник
{}
где угодно , только когда я программировал на C / C ++ около 4 лет .. Это особенно удобно вswitch-case
коде{...}
это более современная разработка на C ++ (помните, что первый C ++, который я использовал, был реализован с помощью препроцессора и не позволял это современное использование). автор был просто олдскулом.Я видел, что он используется как полезный шаблон, когда есть много потенциальных точек выхода для функции, но всегда требуется один и тот же код очистки, независимо от того, как функция завершается.
Это может сделать утомительное дерево if / else-if намного более легким для чтения, просто имея необходимость прерывать работу всякий раз, когда достигается точка выхода, а остальная часть логики встроена впоследствии.
Этот шаблон также полезен для языков, в которых нет оператора goto. Возможно, именно здесь первоначальный программист усвоил шаблон.
источник
Я видел такой код, поэтому вы можете использовать его
break
как своегоgoto
рода.источник
Это просто извращение,
while
чтобы получить семантикуgoto tidy-up
без использования слова goto.Это плохая форма , потому что , когда вы используете другие петли внутри внешний становятся неоднозначными для читателя. «Это должно идти к выходу? Или это предназначено только для выхода из внутреннего цикла?»
while
breaks
источник
Думаю, удобнее писать
break
вместоgoto end
. Вам даже не нужно придумывать название для ярлыка, чтобы прояснить намерение: вы не хотите переходить к ярлыку с определенным именем. Вы хотите уйти отсюда.Также есть вероятность, что скобки вам все равно понадобятся. Итак, это
do{...}while(false);
версия:И вот как вам нужно было бы это выразить, если бы вы хотели использовать
goto
:Я думаю, что смысл первой версии намного легче понять. Также легче писать, проще расширять, легче переводить на язык, который не поддерживает
goto
, и т. Д.Наиболее часто упоминаемое беспокойство по поводу использования
break
заключается в том, что это плохо замаскированоgoto
. Но на самом делеbreak
имеет большее сходство сreturn
: Обе инструкции выходят из блока кода, который в значительной степени структурирован по сравнению сgoto
. Тем не менее, обе инструкции допускают несколько точек выхода в блоке кода, что иногда может сбивать с толку. В конце концов, я бы попытался найти наиболее четкое решение, каким бы оно ни было в конкретной ситуации.источник
do{ ... }while(false);
в целом. Но на самом деле речь идет об использовании его для имитации какой-тоtry{ ... }finally{ ... }
.Этот трюк используют программисты, которые слишком стесняются использовать явное выражение
goto
в своем коде. Автор приведенного выше кода хотел иметь возможность сразу перейти к точке «очистить и вернуть» из середины кода. Но они не хотели использовать ярлык и явноеgoto
. Вместо этого они могут использоватьbreak
внутреннюю часть вышеуказанного «фальшивого» цикла для достижения того же эффекта.источник
Это очень распространенная практика. В С . Я пытаюсь думать об этом так, как будто вы хотите солгать себе таким образом: «Я не использую
goto
». Если подумать, нет ничего плохого в том, чтобыgoto
использовать аналогично. Фактически это также уменьшило бы уровень отступа.Тем не менее, я заметил, что очень часто эти
do..while
петли имеют тенденцию к росту. И тогда они получаютif
s иelse
s внутри, делая код на самом деле не очень читаемым, не говоря уже о тестируемом.Те ,
do..while
как правило , предназначены , чтобы сделать очистку . Во что бы то ни стало, я бы предпочел использовать RAII и раньше возвращаться из короткой функции. С другой стороны, C не предоставляет столько удобства, как C ++ , что делает егоdo..while
одним из лучших подходов к очистке.источник
Похоже на программиста на C. В C ++ автоматические переменные имеют деструкторы, которые вы используете для очистки, поэтому не нужно ничего убирать перед возвратом. В C у вас не было этой идиомы RAII , поэтому, если у вас есть общий код очистки, вы либо
goto
его, либо используете сквозной цикл, как указано выше.Его главный недостаток по сравнению с идиомой C ++ заключается в том, что он не убирается, если в теле возникает исключение. В C не было исключений, так что это не было проблемой, но это стало плохой привычкой в C ++.
источник
Несколько объяснений. Первый - общий, второй - специфичный для макросов препроцессора C с параметрами:
Управление потоком
Я видел, как это использовалось в простом коде C. По сути, это более безопасная версия goto, так как вы можете выйти из нее, и вся память будет очищена должным образом.
Почему что-то вроде
goto
должно быть хорошим? Что ж, если у вас есть код, в котором практически каждая строка может возвращать ошибку, но вам нужно реагировать на все из них одинаково (например, передавая ошибку вызывающему абоненту после очистки), это обычно более читабельно, чтобы избежатьif( error ) { /* cleanup and error string generation and return here */ }
as это позволяет избежать дублирования кода очистки.Однако в C ++ есть исключения + RAII именно для этой цели, поэтому я считаю это плохим стилем кодирования.
Проверка точки с запятой
Если вы забудете точку с запятой после вызова макроса, подобного функции, аргументы могут нежелательным образом сжиматься и компилироваться в допустимый синтаксис. Представьте себе макрос
Это случайно называется
«Еще» будет считаться ассоциироваться с
gDebugModeOn
, так что, когдаfoo
этоfalse
произойдет, произойдет полная противоположность того, что было задумано.Предоставление области для временных переменных.
Поскольку do / while имеет фигурные скобки, временные переменные имеют четко определенную область видимости, из которой они не могут выйти.
Как избежать предупреждений о потенциально нежелательных точках с запятой
Некоторые макросы активируются только в отладочных сборках. Вы определяете их как:
Теперь, если вы используете это в сборке выпуска внутри условного оператора, он компилируется в
Многие компиляторы видят в этом то же, что и
Что часто пишется случайно. Итак, вы получите предупреждение. Do {} while (false) скрывает это от компилятора и принимается им как признак того, что вы действительно хотите здесь ничего делать.
Как избежать захвата строк условными операторами
Макрос из предыдущего примера:
Теперь, в отладочной сборке, поскольку мы обычно включаем точку с запятой, это компилируется нормально. Однако в сборке релиза это внезапно превращается в:
Или более четко отформатированный
Это совсем не то, что было задумано. Добавление do {...} while (false) вокруг макроса превращает отсутствующую точку с запятой в ошибку компиляции.
Что это значит для ОП?
В общем, вы хотите использовать исключения в C ++ для обработки ошибок и шаблоны вместо макросов. Однако в очень редких случаях, когда вам все еще нужны макросы (например, при генерации имен классов с помощью вставки токенов) или вы ограничены простым C, это полезный шаблон.
источник
x =1; y = 2; { int tmp = y; y = x; x = tmp; }
.#define DBG_PRINT_NUM(n) {}
,if(a) DBG_PRINT_NUM(n); else other();
он не будет компилироваться. Допустимо толькоif(a) {} else other();
илиif(a) ; else other();
, ноif(a) {}; else other();
это не так, потому что это делает предложение «if» состоящим из двух операторов.Возможно, он используется для того, чтобы его
break
можно было использовать внутри, чтобы прервать выполнение дальнейшего кода в любой момент:источник
goto
только потому, что кто-то слышал, что это «плохо».Я думаю, что это сделано для использования
break
илиcontinue
операторов. Какая-то логика кода "goto".источник
Все просто: очевидно, вы можете в любой момент выйти из ложного цикла, используя
break
оператор. Кроме того,do
блок - это отдельная область (что также может быть достигнуто с помощью{ ... }
только с помощью).В такой ситуации было бы лучше использовать RAII (объекты автоматически разрушаются правильно, когда функция завершается). Другой подобной конструкцией является использование
goto
- да, я знаю, что это зло , но с ее помощью можно получить общий код очистки, например:(В качестве отступления: конструкция do-while-false используется в Lua для поиска отсутствующего
continue
оператора.)источник
Многие ответившие назвали причину
do{(...)break;}while(false)
. Хотелось бы дополнить картину еще одним примером из жизни.В следующем коде мне пришлось установить перечислитель
operation
на основе адреса, на который указываетdata
указатель. Поскольку сначала switch-case может использоваться только для скалярных типов, я сделал это неэффективно.Но поскольку Log () и остальной код повторяются для любого выбранного значения операции, я блуждал, как пропустить остальные сравнения, когда адрес уже обнаружен. А вот здесь и
do{(...)break;}while(false)
пригодится.Можно задаться вопросом, почему он не мог сделать то же самое
break
вif
заявлении вроде:break
взаимодействует только с ближайшим заключающего цикла или переключателя, будь тоfor
,while
илиdo .. while
тип, поэтому , к сожалению , что не будет работать.источник
Сколько лет было автору?
Я спрашиваю, потому что однажды в конце 80-х я наткнулся на какой-то код на Фортране, который делал это в реальном времени. Оказывается, это действительно хороший способ имитировать потоки в ОС, в которой их нет. Вы просто помещаете всю программу (ваш планировщик) в цикл и вызываете свои «подпрограммы потоков» одну за другой. Сами подпрограммы потоков представляют собой циклы, которые повторяются до тех пор, пока не произойдет одно из ряда условий (часто одно из них - определенное количество время прошло). Это «кооперативная многозадачность», в которой каждый поток должен время от времени отказываться от ЦП, чтобы другие не истощались. Вы можете вложить вызовы подпрограммы цикла для имитации приоритета потока группы.
источник
В дополнение к уже упомянутым примерам goto, идиома do ... while (0) иногда используется в определении макроса, чтобы обеспечить скобки в определении и при этом заставить компилятор работать с добавлением точки с запятой в конец вызов макроса.
http://groups.google.com/group/comp.soft-sys.ace/browse_thread/thread/52f670f1292f30a4?tvc=2&q=while+(0)
источник
Я согласен с большинством постеров об использовании в качестве тонко замаскированного goto. Макросы также упоминались как потенциальная мотивация для написания кода в этом стиле.
Я также видел, как эта конструкция использовалась в смешанных средах C / C ++ как исключение для бедняков. «Do {} while (false)» с «break» можно использовать для перехода к концу блока кода, если в цикле обнаруживается что-то, что обычно требует исключения.
Я также отправил эту конструкцию, используемую в магазинах, где применяется идеология «единого дохода на функцию». Опять же, это вместо явного «goto» - но мотивация состоит в том, чтобы избежать множественных точек возврата, а не «пропустить» код и продолжить фактическое выполнение внутри этой функции.
источник
Я работаю с Adobe InDesign SDK, и в примерах InDesign SDK почти все функции написаны таким образом. Это связано с тем, что функции обычно очень длинные. Где вам нужно выполнить QueryInterface (...), чтобы получить что-либо из объектной модели приложения. Так что обычно каждый QueryInterface сопровождается неудачей
if
, перерыв.источник
Многие уже заявили о сходстве между этой конструкцией и a
goto
и отдали предпочтение goto. Возможно, в прошлом у этого человека была среда, в которой goto были строго запрещены правилами кодирования?источник
Другая причина, о которой я могу думать, заключается в том, что он украшает фигурные скобки, тогда как я считаю, что новые стандартные голые скобки C ++ не подходят (ISO C не любит их). Иначе заглушить статический анализатор вроде пуха.
Не уверен, зачем они вам нужны, возможно, переменная область видимости или преимущество с отладчиком.
См. Раздел « Тривиальный цикл Do While» и « Скобки хороши» из C2.
Чтобы прояснить мою терминологию (которая, как мне кажется, следует стандартному использованию):
Голые брекеты :
Пустые фигурные скобки (NOP):
например
Блок :
который станет
если фигурные скобки удалены, изменяя тем самым поток выполнения, а не только объем локальных переменных. Таким образом, не «отдельно стоящий» или «голый».
Открытые фигурные скобки или блок могут использоваться для обозначения любого раздела кода, который может быть потенциальным для (встроенной) функции, которую вы хотите отметить, но не рефакторинг в то время.
источник
Это надуманный способ подражать a,
GOTO
поскольку эти два практически идентичны:и:
С другой стороны, оба эти действия действительно должны выполняться с помощью
if
s:Хотя вложение может стать немного уродливым, если вы просто превратите длинную строку переадресации
GOTO
во вложенныеif
. Настоящий ответ - это правильный рефакторинг, а не имитация архаичных языковых конструкций.Если вы отчаянно пытались транслитерировать алгоритм с помощью
GOTO
s, вы, вероятно, могли бы сделать это с помощью этой идиомы. Это определенно нестандартно и является хорошим показателем того, что вы не придерживаетесь строго ожидаемых идиом языка.Я не знаю ни одного C-подобного языка, где do / while на самом деле является идиоматическим решением для чего-либо.
Вероятно, вы могли бы реорганизовать весь беспорядок во что-то более разумное, чтобы сделать его более идиоматичным и более читаемым.
источник
do..while(false)
это не для выполнения "неопределенного" количества раз, это для одного выполнения .continue
оператор в конце, как я показал. Кundefined
I просто означает , что вы не знаете , является ли это более чем один раз , если вы не можете предсказать , будет ли выполняться условия , при определенной итерации выполняется. Без каких-либоcontinue
s,do..while(false)
будет запускаться один раз, но также без каких-либоbreak
s в немwhile(true)
будет работать вечно, поэтому «поведение по умолчанию» на самом деле не имеет значения, чтобы понять, что может сделать с циклами.continue
.continue
НЕ повторяет цикл. «continue
Оператор должен встречаться только в операторе итерации и вызывает передачу управления в часть продолжения цикла наименьшего включающего оператора итерации , то есть в конец цикла».Некоторые кодеры предпочитают иметь только один выход / возврат из своих функций. Использование манекена do {....} while (false); позволяет «выйти» из фиктивного цикла после того, как вы закончите, и все еще иметь один возврат.
Я кодировщик Java, поэтому мой пример будет примерно таким:
источник
В таких случаях я использую
источник
Это забавно. Вероятно, внутри цикла есть разрывы, как говорили другие. Я бы сделал это так:
источник
do..while(false)
всегда выходит,while(true)
более рискованно.while(true)
является правильной идиомой для большинства языков. Вы часто найдете его в приложениях с графическим интерфейсом в качестве основного цикла программы. Поскольку вы в основном предполагаете, что программа не должна умереть, пока ей не скажут об этом, ado..while(false)
вызовет всевозможные надуманные логики. Этот подход может быть более рискованным с точки зрения перфекциониста, но он семантически проще и, следовательно, менее подвержен ошибкам для программистов (извините, Скайнет).do{...}while(false)
точно такой же, какwhile(true){ .. break;}
continue
, они не такие.