Newsgroup: it.comp.lang.c++
Titolo: string -> int

Come spesso capita nel formulare la domanda sono riuscito a risolverla!
Devo scrivere una funzione che converte una string a intero. Voglio che 
mi generi un'eccezione se la stringa non contiene un intero.
Il codice seguente funziona, anche se mi sembra un po' macchinoso... vi 
sembra una soluzione sensata? Sapete mica che tipo di eccezione viene 
sollevata? (non è un runtime_error)
int getInt(string name) throw (exception) {
   stringstream s(name);
   int n;
   s.exceptions(ios_base::badbit|ios_base::failbit);
   s>>n;
   if (!s.eof()) s.clear(ios_base::badbit);
   return n;
};
Una domanda a margine. In questo tipo di conversioni mi capitano spesso 
due situazioni:
1 - se la stringa è vuota devo tornare un valore di default (tipicamente 0);
2 - se la stringa è vuota devo sollevare un'eccezione.
Qual è il metodo migliore per gestire entrambe le situazioni? 
Attualmente, nel caso 1, prima controllo se la stringa è vuota e poi 
chiamo la funzione getInt. Però questo è un po' noioso perché mi 
richiede l'utilizzo di una stringa temporanea per il controllo. Potrei 
anche scrivere due versioni di getInt, ma anche questo mi pare un po' 
tedioso. Oltre a getInt ho moltre altre funzioni get... che 
restituiscono i tipi che mi servono, e non vorrei duplicarle tutte.
E.

   stringstream s(name);
uhm, come mai per un compito così semplice e supportato da molte 
varianti di funzioni di libreria, hai pensato ad uno stream (ok, 
è in memoria, ma pursempre un oggetto pesante per un compito 
simile !) ?
c'è qualche motivo per non usare, che so, atoi o atol o analoghe 
(persino sscanf ...)
ciao
Soviet


 (persino sscanf ...)
Probabilmente sbaglio, ma quello che ho pensato è:
- se utilizzo le librerie del C++ cerco di utilizzare solo quelle, senza 
mischiare con la libreria C. Non sono sicuro sia utile, ma se non 
utilizzo mai la sscanf, dovrei risparmiare spazio nell'eseguibile; Eppoi 
  devo includere gli header del C, aumentando il tempo di compilazione...
- siamo sicuri che la atoi o la sscanf sia più veloce?
- ignoranza mia: con atoi o sscanf, come faccio a rilevare un errore? 
Vorrei rilevare un errore anche nella stringa "12 kkk".
forse l'obiezione più ragionevole è la seguente:
- devo anche leggere dei tipi definiti da me, e per questi ho già pronto 
l'operator>>.
Tra l'altro, ho un tipo Vector che viene rappresentato ad esempio da 
"(14.3,5.0)". Per definire l'operator>> ho fatto:
istream &operator>>(istream &in, const Vector &v) {
   return in >> '(' >> v.x >> ',' >> v.y >> ')';
}
con mia sorpresa però l'operatore operator>> non ha predefinita la 
lettura dei char, e neppure dei const char *. Ho dovuto quindi definire io:
istream &operator>>(istream &in, char c) {
   skipws(in);
   if (in.get()!=c)
     s.clear(ios_base::badbit); // mette lo stream in stato bad
   return in;
}
e una cosa simile per
istream &operator>>(istream &in, const char *s) ...
Come mai questi non ci sono nella libreria standard? Sembrerebbero molto 
naturali e comodi...
Ora mi viene in mente che forse operator>>(istream &in,char c) mi oscura 
  operator>>(istream &in, char &c)... però la variante con const char *, 
non dovrebbe dare problemi.
E.

 - ignoranza mia: con atoi o sscanf, come faccio a rilevare un errore ?
non ho ripassato l'help. Mi pare che sscanf ritorni il numero di 
campi acquisiti (secondo lei) con successo.
Come ultima cosa, ammesso che il contesto non si estenda poi a 
input di strutture più complesse, è così tremendo scrivere a 
mano una funzione che legge in input una stringa numerica e la 
controlla ? Lo so che è male, perché è la reinvenzione 
dell'acqua calda, e quando si fa questo si tende a farlo peggio.
Ma potresti giungere a un compromesso. Incapsulare una qualsiasi 
funzione pronta entro un'altra che prima fa un controllo di 
coerenza, e se esso passa con successo delega la conversione di 
tipo alla routine di libreria, viceversa ritorna subito un errore.
Quindi, se hai una stringa di lunghezza nota o misurata pari a X 
caratteri, come prima "indagine" per condizioni di eccezione fai 
una scansione per ogni carattere chiedento se IsNumeric (che è 
una macro) è true. Se passa il controllo fai "cin", istream o 
quel che preferisci. E' un po' più lento, ma almeno sai 
esattamente come lanciarti eccezioni o che altro segnalatore di 
errore usare.
Poi, in tutta onestà, da conoscitore molto superficiale delle 
librerie, ammetto di non sapere se magari già esistono modi per 
controllare i comportamenti generali del lancio di eccezioni, 
gestori etc etc. Su questo passo la palla agli esperti.
ciao
Soviet


 che altro segnalatore di errore usare.
Sì ma questo è ingestibile per tipi più complessi. Pensa anche solo ai 
float tipo 0.5e-34