Conclusão: com o manuseio adequado do espaço em branco, a seguir, é eof
possível usar (e até ser mais confiável do que fail()
a verificação de erros):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( Agradecemos a Tony D pela sugestão de destacar a resposta. Veja o comentário abaixo para um exemplo de por que isso é mais robusto. )
O principal argumento contra o uso eof()
parece estar faltando uma sutileza importante sobre o papel do espaço em branco. Minha proposição é que, verificar eof()
explicitamente não apenas não está " sempre errado " - o que parece ser uma opinião predominante nesse e nos tópicos similares -, mas com o manuseio adequado do espaço em branco, ele fornece um ambiente mais limpo e confiável. tratamento de erros e é a solução sempre correta (embora não necessariamente a mais difícil).
Para resumir o que está sendo sugerido como a ordem de finalização e leitura "adequada", é o seguinte:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
A falha devido à tentativa de leitura além de eof é tomada como condição de finalização. Isso significa que não há uma maneira fácil de distinguir entre um fluxo bem-sucedido e um que realmente falha por outros motivos que não o eof. Tome os seguintes fluxos:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
termina com um conjunto failbit
para todas as três entradas. No primeiro e terceiro, eofbit
também está definido. Portanto, após o loop, é necessário uma lógica extra muito feia para distinguir uma entrada adequada (1ª) das impróprias (2ª e 3ª).
Visto que, faça o seguinte:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Aqui, in.fail()
verifica se, desde que haja algo para ler, é o correto. Seu objetivo não é um mero terminador de loop while.
Até aí tudo bem, mas o que acontece se houver espaço à direita no fluxo - o que parece ser a principal preocupação contra eof()
o terminador?
Não precisamos renunciar ao tratamento de erros; apenas coma o espaço em branco:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
pula qualquer espaço potencial (zero ou mais) à direita no fluxo enquanto define o eofbit
, e não ofailbit
. Portanto, in.fail()
funciona conforme o esperado, desde que haja pelo menos um dado para ler. Se todos os fluxos em branco também forem aceitáveis, o formato correto será:
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
Resumo: Uma construção adequada while(!eof)
não é apenas possível e incorreta, mas permite que os dados sejam localizados no escopo e fornece uma separação mais limpa da verificação de erros dos negócios, como de costume. Dito isto, while(!fail)
é indiscutivelmente um idioma mais comum e conciso, e pode ser preferido em cenários simples (dados únicos por tipo de leitura).
scanf(...) != EOF
também não funcionará em C, porquescanf
retorna o número de campos analisados e atribuídos com êxito. A condição correta éscanf(...) < n
onden
está o número de campos na string de formato.