Плохая практика, это зависит.
То, что я вижу в этом коде, является очень креативным способом написания "goto" с меньшим количеством сернистых ключевых слов.
Существует несколько альтернатив этому коду, которые могут быть или не быть лучше, в зависимости от ситуации.
Ваше решение "сделать / пока"
Ваше решение интересно, если у вас много кода, но в некоторых ограниченных точках будет оцениваться «выход» этой обработки:
do
{
bool isError = false ;
/* some code, perhaps setting isError to true */
if(isError) break ;
/* some code, perhaps setting isError to true */
if(isError) break ;
/* some code, perhaps setting isError to true */
}
while(false) ;
// some other code
Проблема в том, что вы не можете легко использовать свой "if (isError) break;" является циклом, потому что он будет выходить только из внутреннего цикла, а не из блока do / while.
И, конечно, если сбой происходит внутри другой функции, функция должна возвращать какой-то код ошибки, и ваш код не должен забывать правильно интерпретировать код ошибки.
Я не буду обсуждать альтернативы, использующие ifs или даже вложенные ifs, потому что, подумав немного, я нахожу их более низкими решениями, чем ваши, для вашей проблемы.
Вызов goto a ... goto
Возможно, вам следует четко указать на тот факт, что вы используете goto, и документировать причины, по которым вы выбрали это решение вместо другого.
По крайней мере, это покажет, что что-то может быть не так с кодом, и предложит рецензентам утвердить или аннулировать ваше решение.
Вы все равно должны открыть блок и вместо взлома использовать goto.
{
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
while(/* etc.*/)
{
// etc.
for(/* etc.*/)
{
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
}
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
}
// etc.
}
MY_EXIT:
// some other code
Таким образом, когда вы выходите из блока через goto, вы не можете обойти какой-либо конструктор объекта с помощью goto (что запрещено C ++).
Эта проблема решает проблему выхода из вложенных циклов (и использование goto для выхода из вложенных циклов является примером, приведенным Б. Страуструпом как правильное использование goto), но это не решит тот факт, что некоторые вызовы функций могут завершиться с ошибкой и игнорироваться (потому что кто-то не смог правильно проверить свой код возврата, если таковой имеется).
Конечно, теперь вы можете выйти из процесса из нескольких точек, с глубины вложения нескольких циклов, так что если это проблема ...
попытаться / поймать
Если код не должен давать сбой (то есть, сбой является исключительным), или даже если структура кода может дать сбой, но слишком сложен для выхода, тогда следующий подход может быть более понятным:
try
{
// All your code
// You can throw the moment something fails
// Note that you can call functions, use reccursion,
// have multiple loops, etc. it won't change
// anything: If you want to exit the process,
// then throw a MyExitProcessException exception.
if(/* etc. */)
{
// etc.
while(/* etc.*/)
{
// etc.
for(/* etc.*/)
{
// etc.
if(/*some failure condition*/) throw MyExitProcessException() ;
// etc.
}
// etc.
callSomeFunction() ;
// the function will throw if the condition is met
// so no need to test a return code
// etc.
}
// etc.
}
// etc.
}
catch(const MyExitProcessException & e)
{
// To avoid catching other exceptions, you should
// define a "MyExitProcessException" exception
}
// some other code
Если какое-либо условие в коде выше или внутри некоторых функций, вызываемых кодом выше, не выполняется, то генерируется исключение.
Это несколько весомее, чем ваше решение do / while, но имеет те же преимущества и может даже прервать обработку из внутренних циклов или изнутри вызываемых функций.
Обсуждение
Похоже, что ваша потребность проистекает из того факта, что вы можете выполнять сложный процесс (код, вызовы функций, циклы и т. Д.), Но вы хотите прервать его из-за какого-то условия (возможно, из-за сбоя или потому, что он завершился быстрее чем исключено). Если вы можете переписать его по-другому, вы должны это сделать. Но, возможно, другого пути нет.
Давайте предположим, что.
Если вы можете закодировать его с помощью try / catch, сделайте это : Чтобы прервать сложный фрагмент кода, выбрасывание исключения - правильное решение (факт, что вы можете добавить информацию о неудаче / успехе внутри вашего объект исключения не следует недооценивать). После этого у вас будет более понятный код.
Теперь, если вы находитесь в узком месте в скорости, решение вашей проблемы с выброшенными исключениями в качестве выхода не самый быстрый способ сделать это.
Никто не может отрицать, что ваше решение - прославленный гото. Там не будет кода goto-spaghetti, потому что do / while не позволит вам сделать это, но это все же семантическое goto. Это может быть причиной того, что некоторые могут посчитать этот код «плохим»: они чувствуют запах goto, не находя его ключевое слово четко.
Только в этом случае (и в этом исполнении, проверенном профилем) ваше решение выглядит хорошо и лучше, чем альтернатива, использующая if), но более низкого качества (IMHO), чем решение goto, которое, по крайней мере, не ' не может спрятаться за ложной петлей.
Заключение
Насколько я понимаю, я нахожу ваше решение креативным, но я бы придерживался брошенного исключения.
Итак, в порядке предпочтения:
- Используйте try / catch
- Используйте goto
- Используйте цикл do / while
- Использовать ifs / nested ifs