Как вырваться из цикла изнутри коммутатора?
Я пишу код, который выглядит так:
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
break; // **HERE, I want to break out of the loop itself**
}
}
Есть ли какой-либо прямой способ сделать это?
Я знаю, что могу использовать флаг и прерывать цикл, помещая условный разрыв сразу после переключения. Я просто хочу знать, есть ли у С++ какая-то конструкция для этого уже.
Ответы
Ответ 1
Предпосылка
Следующий код следует считать плохим, независимо от языка или желаемой функциональности:
while( true ) {
}
Поддерживающие аргументы
Цикл while( true )
является плохим, потому что он:
- Прерывает подразумеваемый контракт цикла while.
- Объявление цикла while должно явно указывать единственное условие выхода.
- Предполагает, что он будет навсегда.
- Код внутри цикла должен быть прочитан, чтобы понять предложение о прекращении.
- Циклы, которые повторяются навсегда, не позволяют пользователю завершить программу из программы.
- Неэффективен.
- Существует несколько условий завершения цикла, включая проверку "true".
- Является склонным к ошибкам.
- Невозможно определить, где поставить код, который будет выполняться для каждой итерации.
- Приводит к излишне сложному коду.
Альтернатива "Перейти к"
Следующий код лучше выглядит:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Преимущества
Нет флага. Нет goto
. Никаких исключений. Легко изменить. Легко читается. Легко исправить. Кроме того, код:
- Изолирует знание рабочей нагрузки цикла из самого цикла.
- Позволяет кому-то поддерживать код, чтобы легко расширить функциональность.
- Позволяет назначать несколько условий завершения в одном месте.
- Отделяет оканчивающееся предложение от кода для выполнения.
- Безопаснее для АЭС.; -)
Второй момент важен. Не зная, как работает код, если кто-то попросил меня сделать основной цикл, чтобы другие потоки (или процессы) имели некоторое процессорное время, приходят на ум два решения:
Вариант №1
С готовностью вставьте паузу:
while( isValidState() ) {
execute();
sleep();
}
Вариант № 2
Заменить выполнение:
void execute() {
super->execute();
sleep();
}
Этот код проще (поэтому его легче читать), чем цикл со встроенным switch
. Метод isValidState
должен определять только, должен ли цикл продолжаться. Рабочая лошадка метода должна быть абстрагирована на метод execute
, который позволяет подклассам переопределять поведение по умолчанию (сложная задача с использованием встроенных switch
и goto
).
Пример Python
Контрастируйте следующий ответ (на вопрос Python), который был опубликован в StackOverflow:
- Петля навсегда.
- Попросите пользователя ввести свой выбор.
- Если пользовательский ввод является "перезапуском", продолжайте цикл навсегда.
- В противном случае остановите цикл навсегда.
- В конец.
Код
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Versus:
- Инициализировать выбор пользователя.
- Петля, в то время как пользовательский выбор - это слово "перезагрузка".
- Попросите пользователя ввести свой выбор.
- В конец.
Код
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Здесь while True
приводит к вводящему в заблуждение и чрезмерно сложному коду.
Ответ 2
Вы можете использовать goto
.
while ( ... ) {
switch( ... ) {
case ...:
goto exit_loop;
}
}
exit_loop: ;
Ответ 3
Альтернативным решением является использование ключевого слова continue
в сочетании с break
, то есть:
for (;;) {
switch(msg->state) {
case MSGTYPE
// code
continue; // continue with loop
case DONE:
break;
}
break;
}
Используйте оператор continue
, чтобы завершить каждую метку case, где вы хотите, чтобы цикл продолжался, и используйте оператор break
для завершения меток case, которые должны прервать цикл.
Конечно, это решение работает только в том случае, если после инструкции switch нет дополнительного кода.
Ответ 4
Оптимальным способом сделать это было бы включение этого в функцию:
int yourfunc() {
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return;
}
}
}
Необязательно (но "плохие методы" ): как уже было сказано, вы можете использовать goto или исключать исключение внутри коммутатора.
Ответ 5
AFAIK в С++ отсутствует "двойной разрыв" или аналогичная конструкция. Ближайшим будет goto
- который, хотя и имеет плохую коннотацию к его названию, существует на языке по какой-либо причине - если он используется тщательно и экономно, это жизнеспособный вариант.
Ответ 6
Вы можете добавить свой переключатель в отдельную функцию:
bool myswitchfunction()
{
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return false; // **HERE, I want to break out of the loop itself**
}
return true;
}
while(myswitchfunction())
;
Ответ 7
Даже если вам не нравится goto, не используйте исключение для выхода из цикла. Следующий пример показывает, насколько он был бы уродлив:
try {
while ( ... ) {
switch( ... ) {
case ...:
throw 777; // I'm afraid of goto
}
}
}
catch ( int )
{
}
Я бы использовал goto
, как в ответе this. В этом случае goto
сделает код более понятным, чем любой другой вариант. Я надеюсь, что этот будет полезен.
Но я думаю, что использование goto
является единственным вариантом здесь из-за строки while(true)
. Вы должны рассмотреть возможность реорганизации своего цикла. Я бы предположил следующее решение:
bool end_loop = false;
while ( !end_loop ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
end_loop = true; break;
}
}
Или даже следующее:
while ( msg->state != DONE ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
}
Ответ 8
В этом случае нет конструкции С++ для выхода из цикла.
Используйте флаг для прерывания цикла или (при необходимости) извлеките свой код в функцию и используйте return
.
Ответ 9
Вы могли бы использовать goto, но я бы предпочел установить флаг, который останавливает цикл. Затем выйдите из переключателя.
Ответ 10
Почему бы просто не исправить условие в вашем цикле while, из-за чего проблема исчезла?
while(msg->state != DONE)
{
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
// We can't get here, but for completeness we list it.
break; // **HERE, I want to break out of the loop itself**
}
}
Ответ 11
Я думаю:
while(msg->state != mExit)
{
switch(msg->state)
{
case MSGTYPE: // ...
break;
case DONE:
// ..
// ..
msg->state =mExit;
break;
}
}
if (msg->state ==mExit)
msg->state =DONE;
Ответ 12
Самый простой способ сделать это - поставить простой IF до того, как вы сделаете SWITCH, и что IF проверит ваше условие выхода из цикла.......... так просто, как может быть
Ответ 13
Ключевое слово break
в С++ только завершает самую вложенную вложенную итерацию или switch
. Таким образом, вы не могли бы вырваться из цикла while (true)
непосредственно в инструкции switch
; однако вы можете использовать следующий код, который, я думаю, является отличным примером для этого типа проблем:
for (; msg->state != DONE; msg = next_message()) {
switch (msg->state) {
case MSGTYPE:
//...
break;
//...
}
}
Если вам нужно что-то сделать, когда msg->state
равно DONE
(например, запустить процедуру очистки), затем поместите этот код сразу после цикла for
; т.е. если у вас есть:
while (true) {
switch (msg->state) {
case MSGTYPE:
//...
break;
//...
case DONE:
do_cleanup();
break;
}
if (msg->state == DONE)
break;
msg = next_message();
}
Затем используйте вместо этого:
for (; msg->state != DONE; msg = next_message()) {
switch (msg->state) {
case MSGTYPE:
//...
break;
//...
}
}
assert(msg->state == DONE);
do_cleanup();
Ответ 14
Меня поражает, насколько просто это рассматривает глубину объяснений... Здесь все, что вам нужно...
bool imLoopin = true;
while(imLoopin) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
imLoopin = false;
break;
}
}
LOL!! В самом деле! Это все, что вам нужно! Одна дополнительная переменная!
Ответ 15
while(MyCondition) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
MyCondition=false; // just add this code and you will be out of loop.
break; // **HERE, you want to break out of the loop itself**
}
}
Ответ 16
У меня такая же проблема и решена с использованием флага.
bool flag = false;
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
flag = true; // **HERE, I want to break out of the loop itself**
}
if(flag) break;
}
Ответ 17
Нет, у С++ нет конструкции для этого, поскольку ключевое слово "break" уже зарезервировано для выхода из блока переключателя. В качестве альтернативы может существовать do..while() с флагом выхода.
do {
switch(option){
case 1: ..; break;
...
case n: .. ;break;
default: flag = false; break;
}
} while(flag);
Ответ 18
Если я хорошо помню синтаксис С++, вы можете добавить ярлык к операторам break
, как и для goto
. Так что вы хотите легко написать:
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
break outofloop; // **HERE, I want to break out of the loop itself**
}
}
outofloop:
// rest of your code here
Ответ 19
while(true)
{
switch(x)
{
case 1:
{
break;
}
break;
case 2:
//some code here
break;
default:
//some code here
}
}