2016-10-28 13 views
8

Po przeczytaniu wszystkich danych ze strumienia, ale nie próbuję czytać poza jego końcem, strumień EOF strumienia nie jest ustawiony. Tak działają strumienie C++, prawda? To jest powód, to działa:Dlaczego std :: ios_base :: ignore() ustawia bit EOF?

#include <sstream> 
#include <cassert> 

char buf[255]; 

int main() 
{ 
    std::stringstream ss("abcdef"); 
    ss.read(buf, 6); 

    assert(!ss.eof()); 
    assert(ss.tellg() == 6); 
} 

Jeśli jednak zamiast read() ing dane mi ignore() go, EOF jest ustawiona:

#include <sstream> 
#include <cassert> 

int main() 
{ 
    std::stringstream ss("abcdef"); 
    ss.ignore(6); 

    assert(!ss.eof());  // <-- FAILS 
    assert(ss.tellg() == 6); // <-- FAILS 
} 

Jest na GCC 4.8 oraz tułowia GCC (Coliru).

Posiada również niefortunny efekt uboczny wytwarzania tellg() zwrot -1 (bo to co robi tellg()), co jest irytujące dla co robię.

Czy to wymaga normy? Jeśli tak, który fragment i dlaczego? Dlaczego ignore() próbował przeczytać więcej, niż mu powiedziałem?

Nie mogę znaleźć żadnego powodu dla tego zachowania na cppreference's ignore() page. Zamiast tego prawdopodobnie mogę .seekg(6, std::ios::cur), prawda? Ale nadal chciałbym wiedzieć, co się dzieje.

+2

Wow, to działa na MSVS. Oblało to również klir na coliru. Myślę, że może to być biblioteka, a nie sam kompilator. – NathanOliver

+0

co się stanie, jeśli podasz inny 'delim' oprócz' eof'? – dwcanillas

+0

@dwcanillas: [Bez zmian] (http://coliru.stacked-crooked.com/a/bdb33a4a1a87e593). –

Odpowiedz

4

Myślę, że jest to błąd ++ libstdc (42875, h/t NathanOliver). Wymagania dotyczące ignore() w [istream.unformatted] to:

Postacie ekstrahuje aż dowolny z poniższych warunków:
- n != numeric_limits<streamsize>::max() (18.3.2) i n znaków wydobyto dotychczas
- zakończenie -of-file występuje w sekwencji wejściowej (w tym przypadku funkcja wywołuje setstate(eofbit), , która może rzucić ios_base::failure (27.5.5.4));
- traits::eq_int_type(traits::to_int_type(c), delim) dla następnego dostępnego znaku wejściowego c (w takim przypadku zostanie wyodrębnione c).
Uwagi: Ostatni warunek nigdy nie wystąpi, jeśli traits::eq_int_type(delim, traits::eof()).

Mamy więc dwa warunki (ostatni jest ignorowany) - my albo czytać n znaków, lub w pewnym momencie trafiliśmy EOF w takim przypadku możemy ustawić eofbit. Ale możemy odczytać w tym przypadku znaki n ze strumienia (w twoim strumieniu jest 6 znaków), więc nie trafimy końca pliku w sekwencji wejściowej.

W libC++, eof() nie jest ustawiony i tellg() ma powrócić 6.

+0

Cieszę się, że się zgadzasz. :) –

+0

Jak zauważono w raporcie, wymagania są zbyt nieprecyzyjne, aby wyraźnie oznaczyć to błędem w libstdC++, wydaje się bardziej jak usterka standardu. Sformułowanie pozwala prawdopodobnie na wykonanie od pierwszego sprawdzenia, czy trafienie EOF, i tylko sprawdzanie, czy znaki 'n' były już wyodrębnione.Lub sprawdzenie, czy znaki "n" zostały już wyodrębnione, a następnie sprawdzenie, czy trafienie jest EOF, i ostatecznie połączenie wyniku obu kontroli. – hvd

+0

@hvd: Prawdopodobnie. –