Как убежать из цикла из переключателя?

Как другие сказали, Вы не можете надежно обнаружить недопустимый указатель. Рассмотрите некоторые формы, которые мог бы принять недопустимый указатель:

у Вас мог быть нулевой указатель. Это - то, на которое Вы могли легко проверить и сделать что-то о.

у Вас мог быть указатель на где-нибудь за пределами допустимой памяти. То, что составляет допустимую память, варьируется в зависимости от того, как среда выполнения Вашей системы настраивает адресное пространство. В системах Unix это обычно - виртуальное адресное пространство, запускающееся в 0 и идущее в некоторое большое количество мегабайтов. Во встроенных системах это могло быть довольно маленьким. Это не могло бы запуститься в 0 в любом случае. Если Ваше приложение, оказывается, работает в привилегированном режиме или эквиваленте, то Ваш указатель мог бы сослаться на действительный адрес, который может или не может быть сохранен с реальной памятью.

у Вас мог быть указатель на где-нибудь в Вашей допустимой памяти, даже в Вашем сегменте данных, bss, стеке или "куче", но не указывающий на доступный объект. Вариант этого является указателем, который раньше указывал на доступный объект, прежде чем что-то плохо произошло с объектом. Плохие вещи в этом контексте включают освобождение, повреждение памяти или повреждение указателя.

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

проблема становится еще хуже, когда Вы рассматриваете основанную на сегменте/смещении архитектуру и другие нечетные реализации указателя. Этот вид вещи обычно скрыт от разработчика хорошими компиляторами и разумным использованием типов, но если Вы хотите проникнуть в завесу и попытаться перехитрить операционную систему и разработчиков компилятора, ну, в общем, Вы можете, но нет одного универсального способа сделать это, который обработает все проблемы, с которыми Вы могли бы столкнуться.

лучшая вещь, которую можно сделать, позволяют катастрофический отказ и производят некоторую хорошую диагностическую информацию.

107
задан meagar 30 January 2012 в 21:45
поделиться

11 ответов

Предпосылка

Следующий код следует считать плохим тоном, независимо от языка или желаемой функциональности:

while( true ) {
}

Поддерживающие аргументы

Цикл while (true) является плохой формой, потому что он:

  • Разрывает подразумеваемый контракт цикла while. указание начальных условий прерывания позволяет алгоритмам определять полезные инварианты, тем самым улучшая показатели автоматического анализа исходного кода.
  • Бесконечные циклы.
    • Если каждый всегда использует while (true) для циклов, которые являются не бесконечно, мы теряем способность кратко общаться, когда циклы фактически не имеют условия завершения. (Возможно, это уже произошло, поэтому вопрос спорный.)
  • Альтернатива «Перейти к»

    Следующий код является лучшей формой:

    while( isValidState() ) {
      execute();
    }
    
    bool isValidState() {
      return msg->state != DONE;
    }
    

    Преимущества

    Нет флага. Нет goto . Без исключения. Легко поменять. Легко читать. Легко исправить. Дополнительно код:

    1. Изолирует информацию о рабочей нагрузке цикла от самого цикла.
    2. Позволяет кому-то поддерживать код для простого расширения функциональности.
    3. Позволяет назначать несколько условий завершения в одном месте.
    4. Отделяет завершающий раздел от кода для выполнения.
    5. Более безопасен для атомных электростанций. ; -)

    Второй момент важен. Не зная, как работает код, если кто-то попросит меня сделать так, чтобы основной цикл позволял другим потокам (или процессам) иметь некоторое время ЦП, на ум приходят два решения:

    Вариант №1

    Легко вставьте паузу:

    while( isValidState() ) {
      execute();
      sleep();
    }
    

    Вариант № 2

    Выполнение переопределения:

    void execute() {
      super->execute();
      sleep();
    }
    

    Этот код проще (а значит, его легче читать), чем цикл со встроенным переключателем . Метод isValidState должен только определять, следует ли продолжать цикл. Рабочую лошадку метода следует абстрагировать в методе execute ,

    while True: 
        choice = raw_input('What do you want? ')
    
        if choice == 'restart':
            continue
        else:
            break
    
    print 'Break!' 
    

    Versus:

    1. Инициализировать выбор пользователя.
    2. Цикл, пока пользователь выбирает слово «перезапуск».
    3. Попросить пользователя ввести свой выбор.
    4. Конец.
    Код
    choice = 'restart';
    
    while choice == 'restart': 
        choice = raw_input('What do you want? ')
    
    print 'Break!'
    

    Здесь , а True приводит к вводящему в заблуждение и слишком сложному коду.

    53
    ответ дан 24 November 2019 в 03:35
    поделиться

    Вы можете потенциально использовать goto, но я бы предпочел установить флаг, который останавливает петля. Затем выйдите из переключателя.

    2
    ответ дан 24 November 2019 в 03:35
    поделиться

    В C ++ нет конструкции для выхода из цикл в данном случае.

    Либо используйте флаг, чтобы прервать цикл, либо (при необходимости) извлеките свой код в функцию и используйте return .

    5
    ответ дан 24 November 2019 в 03:35
    поделиться

    Насколько я знаю, в C ++ нет «двойного разрыва» или аналогичной конструкции. Наиболее близким будет goto , который, хотя и имеет плохую коннотацию в своем названии, существует в языке по какой-то причине - пока он используется осторожно и экономно, это жизнеспособный вариант.

    14
    ответ дан 24 November 2019 в 03:35
    поделиться

    Изящный способ сделать это - поместить это в функцию:

    int yourfunc() {
    
        while(true) {
    
            switch(msg->state) {
            case MSGTYPE: // ... 
                break;
            // ... more stuff ...
            case DONE:
                return; 
            }
    
        }
    }
    

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

    20
    ответ дан 24 November 2019 в 03:35
    поделиться

    Вы можете использовать goto .

    while ( ... ) {
       switch( ... ) {
         case ...:
             goto exit_loop;
    
       }
    }
    exit_loop: ;
    
    154
    ответ дан 24 November 2019 в 03:35
    поделиться

    Даже если вам не нравится goto, не используйте исключение для выхода из цикла. Следующий пример показывает, насколько это может быть некрасиво:

    try {
      while ( ... ) {
        switch( ... ) {
          case ...:
            throw 777; // I'm afraid of goto
         }
      }
    }
    catch ( int )
    {
    }
    

    Я бы использовал goto как в этот ответ. В этом случае 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 ...
    }
    
    7
    ответ дан 24 November 2019 в 03:35
    поделиться

    Вы можете поместить свой переключатель в отдельную функцию, например это:

    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())
        ;
    
    8
    ответ дан 24 November 2019 в 03:35
    поделиться

    Если я хорошо помню синтаксис C ++, вы можете добавить метку к операторам 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
    
    -2
    ответ дан 24 November 2019 в 03:35
    поделиться

    Альтернативное решение - использовать ключевое слово continue в сочетании с break , то есть:

    for (;;) {
        switch(msg->state) {
        case MSGTYPE
            // code
            continue; // continue with loop
        case DONE:
            break;
        }
        break;
    }
    

    Используйте continue оператор для завершения каждой метки case, в которой вы хотите продолжить цикл, и используйте оператор break для завершения меток case, которые должны завершить цикл.

    Конечно, это решение работает только в том случае, если нет дополнительного кода для выполняется после оператора switch.

    53
    ответ дан 24 November 2019 в 03:35
    поделиться

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

    0
    ответ дан 24 November 2019 в 03:35
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: