Quando o 'ifstream :: readsome' define 'eofbit'?

9

Esse código faz um loop para sempre:

#include <iostream>
#include <fstream>
#include <sstream>

int main(int argc, char *argv[])
{
    std::ifstream f(argv[1]);
    std::ostringstream ostr;

    while(f && !f.eof())
    {
        char b[5000];
        std::size_t read = f.readsome(b, sizeof b);
        std::cerr << "Read: " << read << " bytes" << std::endl;
        ostr.write(b, read);
    }
}

É porque readsome nunca está definindo eofbit .

cplusplus.com diz:

  

Erros são sinalizados ao modificar os sinalizadores de estado interno:

     

eofbit O ponteiro get está no final da entrada interna do buffer de fluxo   array quando a função é chamada, o que significa que não há posições a serem   ler no buffer interno (que pode ou não ser o fim da entrada   seqüência). Isso acontece quando rdbuf()->in_avail() retornaria -1 antes do   primeiro caractere é extraído.

     

failbit O fluxo estava no final da fonte dos caracteres antes do   função foi chamada.

     

badbit Um erro diferente do acima aconteceu.

Quase o mesmo, a norma diz:

  

[C++11: 27.7.2.3]: streamsize readsome(char_type* s, streamsize n);

     

32. Efeitos: se comporta como uma função de entrada não formatada (conforme descrito em   27.7.2.3, parágrafo 1). Depois de construir um objeto de sentinela, se !good() chama    setstate(failbit) , que pode lançar uma exceção e retornar. Caso contrário, extrai   caracteres e armazena-os em localizações sucessivas de um array cujo primeiro   elemento é designado por s . Se rdbuf()->in_avail() == -1 , chamadas    setstate(eofbit) (que pode lançar ios_base::failure (27.5.5.4)) e extrai   sem caracteres;

     
  • Se rdbuf()->in_avail() == 0 , não extrai caracteres
  •   
  • Se rdbuf()->in_avail() > 0 , extrai min(rdbuf()->in_avail(),n)) .
  •   

33. Retorna: O número de caracteres extraídos.

Que a condição in_avail() == 0 é um não-op implica que ifstream::readsome em si é um não-op se o buffer de fluxo estiver vazio, mas a condição in_avail() == -1 implica que será definido eofbit quando alguma outra operação levou a in_avail() == -1 .

Isso parece ser uma inconsistência, mesmo apesar da "natureza" de readsome .

Então, o que é a semântica de readsome e eof ? Eu os interpretei corretamente? Eles são um exemplo de design pobre na biblioteca de transmissões?

(Roubado do [IMO] bug libstdc ++ inválido .)

    
por Lightness Races in Orbit 08.02.2012 в 11:52
fonte

4 respostas

4

Acho que esse é um ponto de personalização, não usado de verdade pelas implementações de fluxo padrão.

in_avail() retorna o número de caracteres que ele pode ver no buffer interno, se houver. Caso contrário, ele chama showmanyc() para tentar detectar se os chars são conhecidos por estarem disponíveis em outro lugar, portanto, é garantido que uma solicitação de preenchimento de buffer seja bem-sucedida.

Por sua vez, showmanyc() retornará o número de caracteres que ele conhece, se houver, ou -1 se souber que uma leitura falhará ou 0 se ela não tiver um pista.

A implementação padrão ( basic_streambuf ) sempre retorna 0, então é isso que você obtém, a menos que você tenha um fluxo com algum outro streambuf sobrescrevendo showmanyc .

O seu loop é essencialmente de leitura-como-muitos-caracteres-como-você-sabe-é-seguro, e fica preso quando isso é zero (significando "não tenho certeza").

    
por Bo Persson 15.02.2012 / 18:06
fonte
1

Se nenhum caractere estiver disponível (por exemplo, gptr() == egptr() para o std:streambuf ), a função de membro virtual showhowmanyc() será chamada. Eu poderia ter uma implementação de showmanyc() , que retorna um código de erro. Por que isso pode ser útil é uma questão diferente. No entanto, isso pode definir eof() . É claro que in_avail() não deve falhar e não bloquear e apenas retornar os caracteres conhecidos disponíveis. Ou seja, o loop que você tem acima é essencialmente garantido como um loop infinito, a menos que você tenha um buffer de fluxo bastante estranho.

    
por Dietmar Kühl 08.02.2012 / 12:13
fonte
1

Eu não acho que o readome () é para o que você está tentando fazer (leia de um arquivo no disco) ... de cplusplus.com:

  

A função destina-se a ser usada para ler dados binários de certas   tipos de fontes assincrônicas que podem esperar por mais caracteres,   pára de ler quando o buffer local esgota, evitando potencial   atrasos inesperados.

Então parece que o readsome () é destinado a fluxos de um soquete de rede ou algo assim, e você provavelmente quer apenas usar read ().

    
por bdow 21.02.2012 / 00:06
fonte
1

Outras pessoas responderam por que readsome não define eofbit pelo design. Vou sugerir uma maneira de ler alguns bytes até eof sem definir fail bit de maneira intuitiva, da mesma maneira que você estava tentando usar readsome . Este é o resultado da pesquisa em outra pergunta .

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

streamsize Read(istream &stream, char *buffer, streamsize count)
{
    // This consistently fails on gcc (linux) 4.8.1 with failbit set on read
    // failure. This apparently never fails on VS2010 and VS2013 (Windows 7)
    streamsize reads = stream.rdbuf()->sgetn(buffer, count);

    // This rarely sets failbit on VS2010 and VS2013 (Windows 7) on read
    // failure of the previous sgetn()
    stream.rdstate();

    // On gcc (linux) 4.8.1 and VS2010/VS2013 (Windows 7) this consistently
    // sets eofbit when stream is EOF for the conseguences  of sgetn(). It
    // should also throw if exceptions are set, or return on the contrary,
    // and previous rdstate() restored a failbit on Windows. On Windows most
    // of the times it sets eofbit even on real read failure
    stream.peek();

    return reads;
}

int main(int argc, char *argv[])
{
    ifstream instream("filepath", ios_base::in | ios_base::binary);
    while (!instream.eof())
    {
        char buffer[0x4000];
        size_t read = Read(instream, buffer, sizeof(buffer));
        // Do something with buffer 
    }
}
    
por ceztko 30.04.2018 / 11:15
fonte