Eu sou um programador autodidata. Comecei a programar cerca de 1,5 anos atrás. Agora comecei a ter aulas de programação na escola. Tivemos aulas de programação por 1/2 ano e agora temos outras 1/2.
Nas aulas, estamos aprendendo a programar em C ++ (que é uma linguagem que eu já sabia usar bastante antes de começarmos).
Não tive dificuldades durante esta aula, mas há um problema recorrente para o qual não consegui encontrar uma solução clara.
O problema é o seguinte (em Pseudocódigo):
do something
if something failed:
handle the error
try something (line 1) again
else:
we are done!
Aqui está um exemplo em C ++
O código solicita que o usuário insira um número e o faz até que a entrada seja válida. Ele usa cin.fail()
para verificar se a entrada é inválida. Quando cin.fail()
é que true
eu tenho que ligar cin.clear()
e cin.ignore()
poder continuar a receber informações do fluxo.
Estou ciente de que esse código não faz check-in
EOF
. Os programas que escrevemos não devem fazer isso.
Aqui está como eu escrevi o código em uma das minhas tarefas na escola:
for (;;) {
cout << ": ";
cin >> input;
if (cin.fail()) {
cin.clear();
cin.ignore(512, '\n');
continue;
}
break;
}
Meu professor disse foi que eu não deveria estar usando break
e continue
como esta. Ele sugeriu que eu deveria usar um regular while
ou do ... while
loop.
Parece-me que usar break
e continue
é a maneira mais simples de representar esse tipo de loop. Na verdade, eu pensei sobre isso por um bom tempo, mas não encontrei uma solução mais clara.
Eu acho que ele queria que eu fizesse algo assim:
do {
cout << ": ";
cin >> input;
bool fail = cin.fail();
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (fail);
Para mim, esta versão parece muito mais complexa, pois agora também temos chamadas de variáveis fail
para acompanhar e a verificação de falha de entrada é feita duas vezes em vez de apenas uma vez.
Também imaginei que posso escrever o código dessa maneira (abusando da avaliação de curto-circuito):
do {
cout << ": ";
cin >> input;
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (cin.fail() && (cin.clear(), cin.ignore(512, '\n', true);
Esta versão funciona exatamente como as outras. Ele não usa break
ou continue
e o cin.fail()
teste é feito apenas uma vez. Contudo, não me parece correto abusar da "regra de avaliação de curto-circuito" como esta. Eu também não acho que meu professor gostaria.
Esse problema não se aplica apenas à cin.fail()
verificação. Eu usei break
e continue
assim para muitos outros casos que envolvem a repetição de um conjunto de códigos até que uma condição seja atendida, onde algo também deve ser feito se a condição não for atendida (como chamar cin.clear()
e a cin.ignore(...)
partir do cin.fail()
exemplo).
Eu continuei usando break
e continue
ao longo do curso e agora meu professor parou de reclamar.
Quais são as suas opiniões sobre isso?
Você acha que meu professor está certo?
Você conhece uma maneira melhor de representar esse tipo de problema?
while (true)
e imediatamente supor que há um break
, return
ou throw
em algum lugar lá. A introdução de uma variável extra que precisa ser monitorada apenas para evitar uma break
ou continue
é contraproducente. Eu argumentaria que o problema com o código inicial é que o loop nunca termina uma iteração normalmente e que você precisa saber que há um continue
detalhe interno if
para saber break
que não será utilizado.
dataIsValid
é mutável, para saber que o loop termina corretamente, preciso verificar se está definido quando os dados são válidos e também se não está desabilitado em nenhum momento posteriormente. Em um loop do formulário, do { ... if (!expr) { break; } ... } while (true);
eu sei que, se for expr
avaliado false
, o loop será interrompido sem ter que olhar para o resto do corpo do loop.