2016-10-28 1 views
8

Lorsque je lis toutes les données d'un flux, mais ne tente pas de lire au-delà de sa fin, le flux EOF n'est pas défini. C'est comme ça que fonctionnent les flux C++, n'est-ce pas? C'est la raison pour laquelle cela fonctionne:Pourquoi std :: ios_base :: ignore() définit le 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); 
} 

Cependant, si au lieu de read() données ing je ignore() il, EOF est définie:

#include <sstream> 
#include <cassert> 

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

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

Ceci est le GCC 4.8 et le tronc GCC (Coliru).

Il a également effet secondaire malheureux de faire tellg() retour -1 (parce que ce tellg() fait), ce qui est gênant pour ce que je fais.

Est-ce que cette norme est obligatoire? Si oui, quel passage et pourquoi? Pourquoi est-ce que ignore() tenterait de lire plus que je ne le lui avais dit?

Je ne trouve aucune raison pour ce comportement sur cppreference's ignore() page. Je peux probablement .seekg(6, std::ios::cur) à la place, non? Mais j'aimerais quand même savoir ce qui se passe.

+2

Wow, cela fonctionne sur VSM. Il a également échoué avec clang sur coliru. Je pense que ce pourrait être la bibliothèque et non le compilateur lui-même. – NathanOliver

+0

que se passe-t-il si vous spécifiez un 'delim' différent de' eof'? – dwcanillas

+0

@dwcanillas: [Pas de changement] (http://coliru.stacked-crooked.com/a/bdb33a4a1a87e593). –

Répondre

4

Je pense qu'il s'agit d'un bogue libstdC++ (42875, h/t NathanOliver). Les exigences relatives à ignore() [istream.unformatted] sont les suivants:

caractères sont extraits jusqu'à ce que tout des cas suivants:
- n != numeric_limits<streamsize>::max() (18.3.2) et n caractères ont été extraits jusqu'à présent
- fin -de-fichier se produit sur la séquence d'entrée (dans ce cas la fonction appelle setstate(eofbit), qui peut lancer ios_base::failure (27.5.5.4)); Pour le caractère d'entrée disponible suivant
Remarques: La dernière condition ne se produira jamais si traits::eq_int_type(delim, traits::eof()).

Nous avons donc deux conditions (la dernière est ignorée) - nous soit lu n caractères, ou à un moment donné nous avons atteint la fin de fichier auquel cas nous avons mis la eofbit. Mais, nous sommes en mesure de lire n caractères du flux dans ce cas (il y a en fait 6 caractères dans votre flux), donc nous ne frapperons pas la fin-de-fichier sur la séquence d'entrée.

En libC++, eof() n'est pas réglé et tellg() ne retourne 6.

+0

Je suis content que vous soyez d'accord. :) –

+0

Comme indiqué dans le rapport, les exigences sont trop vagues pour identifier clairement ce bug dans libstdC++, cela ressemble plus à un défaut de la norme. Le libellé permet sans doute à une implémentation de vérifier d'abord si EOF est touché, et de vérifier seulement si les caractères 'n' ont déjà été extraits après cela.Ou en vérifiant si les caractères 'n' ont déjà été extraits, puis en vérifiant si EOF est frappé, et enfin en combinant le résultat des deux vérifications. – hvd

+0

@hvd: Sans doute. –