Perché lo stringstream >> cambia il valore dell’objective in caso di fallimento?

Dal TC ++ di Stroustrup, terza edizione, Sezione 21.3.3:

Se proviamo a leggere in una variabile v e l’operazione fallisce, il valore di v dovrebbe essere invariato (non è cambiato se v è uno dei tipi gestiti da istream o da funzioni membro ostream).

L’esempio seguente sembra contraddire la citazione precedente. Sulla base della citazione di cui sopra, mi aspettavo che il valore di v rimanesse invariato, ma viene azzerato. Qual è la spiegazione di questo apparente comportamento contraddittorio?

#include  #include  int main( ) { std::stringstream ss; ss << "The quick brown fox."; int v = 123; std::cout << "Before: " << v <> v ) { std::cout << "Strange -- was successful at reading a word into an int!\n"; } std::cout << "After: " << v << "\n"; if( ss.rdstate() & std::stringstream::eofbit ) std::cout << "state: eofbit\n"; if( ss.rdstate() & std::stringstream::failbit ) std::cout << "state: failbit\n"; if( ss.rdstate() & std::stringstream::badbit ) std::cout << "state: badbit\n"; return 1; } 

L’output che ottengo usando x86_64-w64-mingw32-g ++. Exe (rubenvb-4.7.2-release) 4.7.2 è:

 Before: 123 After: 0 state: failbit 

Grazie.

Da questo riferimento :

Se l’estrazione non riesce (ad esempio se è stata immessa una lettera in cui è prevista una cifra), il valore non viene modificato e viene impostato failbit ( fino a C ++ 11 )

Se l’estrazione fallisce, zero viene scritto in valore e viene impostato failbit. Se l’estrazione risulta nel valore troppo big o troppo piccolo per adattarsi al valore, std :: numeric_limits :: max () o std :: numeric_limits :: min () viene scritto e viene impostato il flag fail-bit. ( dal C ++ 11 )

Sembra che il compilatore stia compilando in modalità C ++ 11, che cambia il comportamento.


L’operatore di input usa il facet delle std::num_get internazionali std::num_get cui funzione get richiama do_get . Per C ++ 11 è specificato l’uso di std::strtoll et. al. tipo di funzioni. Prima di C ++ 11 apparentemente si usava l’analisi di stile std::scanf (passando per il riferimento, non ho accesso alle specifiche C ++ 03) per estrarre i numeri. Il cambiamento nel comportamento è dovuto a questa modifica nell’analisi dell’input.

L’operatore >> è un operatore di input formattato.
Come tale dipende dalla localizzazione per come l’input viene letto dallo stream:

[Istream.formatted.arithmetic]

Come nel caso degli inseritori, questi estrattori dipendono dall’object num_get <> (22.4.2.1) locale per eseguire l’analisi dei dati del flusso di input. Questi estrattori si comportano come funzioni di input formattate (come descritto in 27.7.2.2.1). Dopo la costruzione di un oggetto sentry, la conversione avviene come se fosse eseguita dal seguente frammento di codice:

  typedef num_get< charT,istreambuf_iterator > numget; iostate err = iostate::goodbit; use_facet< numget >(loc).get(*this, 0, *this, err, val); setstate(err); 

Come possiamo vedere sopra, il valore viene effettivamente impostato dal numget faccette delle località inserite nello stream.

num_get funzioni virtuali [facet.num.get.virtuals]

Fase 3:

Il valore numerico da memorizzare può essere uno di:

  • zero, se la funzione di conversione non riesce a convertire l’intero campo. ios_base :: failbit è assegnato a err.
  • il valore rappresentabile più positivo, se il campo rappresenta un valore troppo grande positivo da rappresentare in val. ios_base :: failbit è assegnato a err.
  • il valore rappresentativo più negativo o zero per un tipo intero senza segno, se il campo rappresenta un valore troppo grande negativo da rappresentare in val. ios_base :: failbit è assegnato a err.

La definizione di fase 3 è cambiata drasticamente tra n2723 -> n2798

Dove trovo gli attuali documenti standard C o C ++?

num_get funzioni virtuali [facet.num.get.virtuals]

Fase 3: il risultato dell’elaborazione della fase 2 può essere uno di:

  • Una sequenza di caratteri è stata accumulata nello stage 2 che viene convertita (secondo le regole di scanf) in un valore del tipo di val. Questo valore è memorizzato in val e ios_base :: goodbit è memorizzato in err.
  • La sequenza di caratteri accumulata nella fase 2 avrebbe causato che scanf segnalasse un errore di input. ios_base :: failbit è assegnato a err.