É possível sair de um para antes do tempo em C ++, se uma condição de término é alcançada?

StackOverflow https://stackoverflow.com/questions/416464

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu quero saber se é possível para acabar com um loop em C ++ quando uma condição final (diferente do número reacheing direito de iterações) é verificada. Por exemplo:

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.

Eu sei que isso é possível em Perl com a próxima etiqueta ou última etiqueta chamadas e blocos marcados, é possível fazê-lo em C ++ ou devo usar um tempo loop?

Obrigado.

Foi útil?

Solução

Você pode usar a palavra-chave return:. Mover o loop aninhado em uma sub-rotina, invocar a sub-rotina para executar os loops aninhados, e 'retorno' da sub-rotina para sair [todos] os laços

Outras dicas

Apesar dos "goto considerados prejudiciais" argumentos, este parece ser o lugar perfeito para goto. Isso é essencialmente o que você está fazendo em Perl. Sério ... considerar as alternativas:

Variáveis ?? Estado extra


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
    }
}

Deixe por Exceção


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&) {
}

Logic Complexo


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:

é o último menos claro? Eu não acredito que ele é. É mais frágil? IMHO, os outros são muito propenso a erros e frágil em comparação com a versão goto. Desculpe a ser pé no palanque aqui, mas isso é algo que tem me incomodado por um tempo;)

A única coisa que você tem que ser congnizent é que goto e exceções são bastante semelhantes. Ambos abrir a oportunidade para vazamento de recursos eo que não para tratá-los com cuidado.

Deixe-me dizer isso como enfaticamente (mas educadamente ;-) quanto eu puder:. A construção for em c-como língua não é sobre a contagem

A expressão de teste que determina se continuar pode ser qualquer coisa que seja relevante para o propósito do loop; a expressão actualização não tem de ser "adicionar um para um contador".

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

seria uma forma (bastante arbitrária) para reescrever.

O ponto é que, se estabelecer alguma condição é o ponto de uma interação, geralmente é possível escrever um loop (usando while ou for) de uma forma que afirma a continuar / cancelar condição mais explicitamente.

(Se você pudesse postar uma descrição do que está realmente acontecendo, é provável que escrever algo que não parece tão arbitrário como o acima.)

Você não pode saltar de dois laços com uma única instrução pausa, mas você poderia usar um goto para saltar do lado de fora direita loop interno.

Se o Goto está localizada, e significa que há menos lógica do que o contrário eu acho que é perfeitamente código aceitável. Tendo variáveis ??bandeira extras, ou içar a variável de iterador fora do circuito interno para que você possa compará-lo no loop externo não faz para fácil de entender IMHO código.

De todas as sugestões acima gostaria de evitar o uso do mecanismo de try / catch porque as exceções devem ser reservados para circunstâncias excepcionais, e não de controle de fluxo normal.

Usando duas quebras é tudo bem se você pode criar a segunda condição adequada. Usando um booleano para este fim também seria bom, e você pode até mesmo conectar-lo na condição de cada loop. Por exemplo:

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;
    }
}

Embora se você estiver usando mais de duas voltas que poderia ser mais apropriado para envolvê-los em uma função e usar apenas retorno para sair da função (e todos os loops também). Em seguida, novamente você poderia refatorar o código de uma forma que pode eliminar todos, mas um dos loops, seja por chamar uma função para executar o código de loop interno, etc.

Por último, não tenha medo de usar um goto nesta circunstância, geralmente de empreendedores são ruins programação não estruturada, mas em alguns casos (como este) são muito úteis.

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 {
        }

Ou você poderia apenas Goto. Ou não: -)

Você não pode saltar para fora como este em C / C ++:

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

sem o uso de Goto. Você precisa de uma construção como:

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

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

Como alternativa, use jogar e pegar -. Mas isso não é grande desde lance deve realmente ser usado para exceções e não controle de fluxo

Uma maneira limpa é fazer com que o loop interno uma função:

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

void G ()
{
  for (...)
  {
    if (!F ())
    {
      break;
    }
  }
}
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
}

Você pode usar um Goto declaração , mas que é geralmente considerado uma má prática.

Sua outra opção é fazer algo como isto

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)

código de leitura não deve ser como ler um livro de detetive (que sempre precisa ser descoberto) ...

Por exemplo:

Java:

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;
    }   
}

Você não precisa descobrir o que iterate_rows quebrar não, você apenas lê-lo.

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:;

Goto break_iterate_rows é apenas um visível versão do pausa iterate_rows

Se você limitar o seu uso de Goto e etiquetas sobre este tipo de único código, você não vai ser descobrir a intenção. Limitando o uso de Goto e etiquetas sobre este tipo de código fará com que você acabou de ler o código, não analisar ou descobrir isso. Você não vai ser acusado de ser um programador mal.

E se você realmente limitar suas gotos neste tipo de código, você vai ser capaz de desenvolver um hábito de não precisar descobrir o que essas gotos danado fazer em seu código. benefício adicional é que você não tem que introduzir booleans e acompanhá-los (que IMHO, leva a detectar o código , tornando-o um pouco ilegível, que derrota o propósito de gotos evitando)

P.S.

Par esses rótulos com comentários (antes do loop), pelo tempo que você ler além daquelas linhas com Goto declaração que você já sabe a intenção daqueles gotos

Eu tenho algumas sugestões:

  1. lance .... colocar os dois loops dentro de um "try {}" e "pegar" a "jogar" com a condição.

  2. colocar os dois loops em um método e um retorno sobre a condição.

  3. Goto não é mal seus Utilizar as pessoas colocam-lo também .... Você pode usar "goto" pode ser o código mais claro, especialmente quando lidam com erros. Eu não usei um em cada 20 anos.

Tony

Eu sempre tentei ficar longe de declarações goto (foi sempre olhou para cima na escola e meu trabalho por algum motivo). Gostaria de usar algo como o que Daemin sugeriu.

Você pode usar rótulos, algo ao longo das linhas de:

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

Em Java você pode passar rótulos para quebrar eu acho?

Edit - Mudou o Goto para End em vez de Outer, no entanto eu não acho que o representante negativo é justificado. Essa resposta dá a maneira mais simples de fazê-lo.

Outra razão para reconsiderar a construo for inteiramente é que as suas impede escopo aceder às variáveis ??controladas após o ciclo tenha terminado. O valor (es) da variável (s) a ser mutado no circuito pode útil para uma variedade de razões (por exemplo, para distinguir o sucesso do fracasso em uma pesquisa) que de outro modo requerem variáveis ??adicionais para preservar a informação de que após a saída alcance. Aqui está um pequeno exemplo que procuras uma matriz quadrada chamado a para um valor target (assumindo que SIZE é diferente de zero, caso contrário, nenhuma pesquisa é necessário!):

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;
    }
}

O código posterior pode usar i < SIZE para determinar se o valor desejado foi localizado.

Outra vantagem do acima é a flexibilidade. Suponha agora estamos informados de que os valores em linhas de a estão subindo, então o restante de uma linha é irrelevante se um valor maior do que target é encontrado. É fácil saber exatamente o que a mudança de fazer, e onde fazer isso. Porque essa nova informação nos permite abandonar a linha atual, apenas a decisão interna é afetada, tornando-se:

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

Eu estou vendo mais das línguas mais recentes (especialmente os orientados funcionalmente) abandonando o velho "contagem" construção de loop; isso é provavelmente uma coisa boa, uma vez que nos encoraja a pensar sobre o significa do loop, em vez de simplesmente contar.

A melhor maneira que eu vi envolve macros e gotos, mas é realmente muito nice (ligada à começa pós falando sobre Perl, mas o último parágrafo ou assim introduz as macros).

Ele permite que você escrever código como:

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);
        }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top