Можно ли выйти из за до времени в C ++, если окончание состояние достигается?

голоса
7

Я хочу знать, если это возможно, чтобы закончить цикл в C ++, когда заканчивается условие (отличаются от reacheing правильного числа итераций) проверяются. Например:

for (int i = 0; i < maxi; ++i)
    for (int j = 0; j < maxj; ++j)
        // But if i == 4 < maxi AND j == 3 < maxj, 
        // then jump out of the two nested loops.

Я знаю, что это возможно в Perl с рядом LABEL или последним LABEL вызовов и меченых блоков, можно сделать это в C ++ или я должен использовать время цикла?

Спасибо.

Задан 06/01/2009 в 14:16
источник пользователем
На других языках...                            


15 ответов

голоса
51

Вы можете использовать returnключевое слово: переместить вложенный цикл в подпрограмму, вызовите подпрограмму для запуска вложенных циклов, и «возвращение» из подпрограммы , чтобы выйти из [все] петли.

Ответил 06/01/2009 в 14:33
источник пользователем

голоса
47

Несмотря на « gotoсчитаются вредными» аргументы, это кажется идеальным местом для goto. Это в основном то , что вы делаете в Perl. Серьезно ... рассмотреть альтернативные варианты:

Дополнительные переменные состояния


for (int i=0; i<maxi; ++i) {
    bool leaveLoop = false;
    for (int j=0; j<maxj; ++j) {
        if (i == 4 && j == 3) {
            leaveLoop = true;
            break; // leave the inner loop
        }
    }
    if (leaveLoop) {
        break; // leave the outside loop
    }
}

Оставить по отклонениям


try {
    for (int i=0; i<maxi; ++i) {
        for (int j=0; j<maxj; ++j) {
            if (i == 4 && j == 3) {
                throw leave_loop();
            }
        }
    }
} catch (leave_loop const&) {
}

Комплексная логика


int j = 0;
for (int i=0; i<maxi && !(i==4 && j==3); ++i) {
    for (j=0; j<maxj && !(i==4 && j==3); ++j) {
        // inner loop
    }
}

goto


for (int i=0; i<maxi; ++i) {
    for (int j=0; j<maxj; ++j) {
        if (i==4 && j==3) {
            goto leave_loop;
        }
    }
}
leave_loop:

Является последним менее ясно? Я не считаю , что это. Стоит ли более хрупким? ИМХО, остальные весьма подвержены ошибкам и хрупкие по сравнению с gotoверсией. К сожалению , чтобы стоять на мыльнице здесь , но это то , что надоела меня на некоторое время;)

Единственное , что вы должны быть congnizent из что gotoи исключения очень похожи. Они оба открывают возможность для утечки ресурсов и что не так относиться к ним с осторожностью.

Ответил 06/01/2009 в 14:45
источник пользователем

голоса
13

Позвольте мне сказать это так настойчиво (но вежливо ;-) как я могу: конструкт в С-подобный язык не о подсчете.for

Выражение тест, который определяет, следует ли продолжать может быть любым, которое имеет отношение к цели цикла; выражение обновление не должно быть «добавьте к счетчику».

for (int i = 0, j = 0; i < maxi && j < maxj && i != 4 && j != 3;) {
    if (j < maxj) {
        ++j;
    } else {
        j = 0;
        ++i;
    }
}

будет один (достаточно произвольно) способ переписать.

Дело в том , что если установить какое - либо условие является точкой из Интерактивных, обычно можно написать цикл ( с использованием либо whileили for) таким образом , что говорится о продолжении / прекращении условия более явно.

(Если бы вы могли опубликовать описание того, что происходит на самом деле, это, вероятно, чтобы написать что-то, что не выглядит произвольным, как указано выше.)

Ответил 06/01/2009 в 14:31
источник пользователем

голоса
8

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

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

bool exit_loops = false;
for (int a = 0; a < A && !exit_loops; ++a)
{
    for (int b = 0; b < B && !exit_loops; ++b)
    {
        if (some_condition) exit_loops = true;
    }
}

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

И, наконец, не бойтесь использования Готы в этом обстоятельстве, как правило, Гото плохо неструктурированное программирование, но в некоторых случаях (как это), они очень полезны.

Ответил 06/01/2009 в 14:48
источник пользователем

голоса
8

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

Если Гото локализовано, а значит, есть меньше логики, чем в противном случае я думаю, что это вполне приемлемы коды. Наличие дополнительных переменных флагов, или грузоподъемных переменной итератора из внутреннего цикла, так что вы можете сравнить его во внешнем контуре не делает для проще понять код ИМХО.

Ответил 06/01/2009 в 14:22
источник пользователем

голоса
6
bool done = false;

for (int i = 0; i < maxi && !done; ++i)
    for (int j = 0; j < maxj && !done; ++j)
        if (i == 4 && i < maxi && j == 3 && j < maxj )
             done = true;
        else {
        }

Или вы могли бы просто перейти. Или нет :-)

Ответил 06/01/2009 в 14:47
источник пользователем

голоса
6

Вы не можете выскочить, как это в C / C ++:

for (...)
{
  for (...)
  {
    // from here...
  }
}
// ...to here

без использования Гото. Вам нужна конструкция, как:

for (...)
{
  bool
    exit = false;

  for (...)
  {
    if (do_exit)
    {
      exit = true; // or set outer loop counter to end value
      break;
    }
  }
  if (exit)
  {
    break;
  }
}

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

Чистый способ это сделать внутренний цикл функции:

bool F ()
{
  if inner loop terminates, return false else return true
}

void G ()
{
  for (...)
  {
    if (!F ())
    {
      break;
    }
  }
}
Ответил 06/01/2009 в 14:25
источник пользователем

голоса
4

Вы можете использовать Гото заявление , но это обычно считается плохой практикой.

Другой вариант это сделать что-то вроде этого

int i;
int j = 0;
for (i = 0; i < maxi && !(i==4 && j==3); ++i)
    for (j = 0; j < maxj && !(i==4 && j==3); ++j)
Ответил 06/01/2009 в 14:22
источник пользователем

голоса
4
for (int i = 0; i < maxi; ++i)
{
    int j = 0;
    for (j = 0; j < maxj; ++j)
    {
         if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
             break; // exit inner loop
    }
    if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
        break; // exit outer loop
}
Ответил 06/01/2009 в 14:22
источник пользователем

голоса
2

Чтение кода не должна быть, как чтение детектива книги (которая всегда нужно быть просчитана) ...

пример:

Ява:

iterate_rows:
for (int i = 0; i < maxi; ++i)
{       
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            break iterate_rows;
        else
            continue iterate_rows;
    }   
}

Вам не нужно, чтобы понять, что перерыв iterate_rows делать, вы просто читать.

C ++:

//iterate_rows:
for (int i = 0; i < maxi; ++i)
{
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            goto break_iterate_rows;
        else
            goto continue_iterate_rows;
    }

continue_iterate_rows:;
}
break_iterate_rows:;

Гото break_iterate_rows просто видна версия iterate_rows излома

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

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

PS

Пара этих меток с комментариями (до цикла), к тому времени, когда Вы читаете эти строки мимо с Гото заявлением вы уже знаете намерения этих GOTOS

Ответил 06/01/2009 в 16:11
источник пользователем

голоса
1

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

Это позволяет писать код, как:

named (LOOPS) for (i=1; i<10; i++) {
    for (j=1; j<10; j++) {
        for (j=1; j<10; j++) {
            /* Process data[i][j][k] here */
            if (data[i][j][k] < threshold) break(LOOPS);
        }
    }
}
Ответил 06/01/2009 в 20:26
источник пользователем

голоса
1

Еще одна причиной для пересмотра forконструкции полностью является то , что его обзорным предотвращает доступ к контролируемому переменным после того , как цикл завершается. Значение (ы) переменный (ами) , которые мутировали в цикле может полезно для различных причин (например , чтобы отличить успех от неудачи в поиске) , которые иначе требуют дополнительных переменных , чтобы сохранить эту информацию после выхода области видимости. Вот небольшой пример , который ищет квадратный массив с именем aдля targetзначения (при условии , что SIZEне равен нулю, в противном случае поиск не надо!):

int i = 0;
int j = 0;
while (i < SIZE && a[i][j] != target) { // still in array but not at target
    if (SIZE <= ++j) {                  // fallen off the end of a row
        j = 0;
        ++i;
    }
}

Последующий код можно использовать i < SIZEдля определения того , находится ли требуемое значение.

Еще одним преимуществом выше является гибкость. Предположим , что мы теперь о том , что значения в строках aвосходящие, так что остальная часть строки не имеет значения , если значение больше , чем targetвстречается. Это легко , чтобы точно знать , что изменить , чтобы сделать, и где это сделать. Потому что новая информация позволяет отказаться от текущей строки, только внутреннее решение зависит, став:

    if (target < a[i][j] || SIZE <= ++j) { // can't be in row or fallen off end
    ...

Я вижу больше новых языков (особенно функционально-ориентированные) , отказавшихся старую «подсчет» конструкцию цикла; это, наверное, хорошо, поскольку это заставляет нас думать о значении цикла, а не просто считать.

Ответил 06/01/2009 в 19:36
источник пользователем

голоса
1

Я всегда старался держаться подальше от gotoзаявлений (всегда смотрели свысока в школе , и моя работа по какой - то причине). Я хотел бы использовать что - то вроде того, что предложил Daemin.

Ответил 06/01/2009 в 15:02
источник пользователем

голоса
1

У меня есть несколько предложений:

  1. бросить .... положить две петли внутри «пробным {}», а затем «поймать» «бросок» на состояние.

  2. положить две петли в методе и вернуться на состояние.

  3. Goto не является злом его на использовании люди положить его слишком .... Вы можете использовать «Готы» может быть ярчайшим кодом, особенно при обработке ошибок. Я не использовал один в 20 лет.

Тони

Ответил 06/01/2009 в 14:31
источник пользователем

голоса
1

Вы можете использовать метки, то вдоль линий:

Outer:
for(...)
{
    Inner:
    for(...)
    {
    if(condition)
        {
        goto End;
        }
    }
}
End:

В Java вы можете передать этикетки сломать я думаю?

Edit - Изменена Гото покончим, а не внешний, однако я не думаю, что негативная репутация оправдана. Этот ответ дает самый простой способ сделать это.

Ответил 06/01/2009 в 14:20
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more