Gli stream del C++ e le eccezioni
Molti programmatori utilizzano l'accesso ai file (sequenziali) in stile C piuttosto che in stile C++.
Author: Mario Graziosi, mgnospam@fgasoftware.com
Molti programmatori utilizzano l'accesso ai file (sequenziali) in stile C piuttosto che in stile C++. E' comprensibile che un programmatore che arriva dal 'C' si trovi più a proprio agio con una semplice fopen(), però è un peccato che le innovazioni della libreria dell'ANSI C++ non vengano sfruttate. Il mio consiglio, a tutti gli sviluppatori che passano al C++, è quello di abituarsi al nuovo stile. Vediamone alcuni vantaggi.
(1) è più robusto perchè garantisce la distruzione degli oggetti. Per esempio, se in un blocco vogliamo esere sicuri che il file venga chiuso, è sufficiente istanziarlo sullo stack (se viene istanziato come static la chiusura viene in ogni caso garantita a fine programma):
if (/* qualcosa*/)nel codice sopra apro il file PIPPO.DAT ma non lo chiudo. Verrà chiuso in ogni caso quando "myfile" perderà visibilità. Verrà chiuso automaticamente anche se la funzione dovesse essere abbandonata n modo prematuro a causa di eccezioni.
{
ofstream myfile("pippo.dat");
while (!myfile.eof())
; // Processo i dati
}
(2) è possibile estendere il nuovo stile di I/O abbastanza facilmente aggiungendo l'operatore<<. Per esempio, se volessi supportare una mia classe "Cliente", potrei scrivere qualcosa come:
Cliente cli;L'operatore<< sarebbe definito più o meno così:
myfile << cli << endl;
/*friend*/ ostream& operator<<(ostream& os, const Cliente& x)In questo modo otterrei del codice più leggibile ed anche più manutenibile visto che, se dovessi cambiare la strategia di registrazione del Cliente, la logica sarebbe isolata nell'apposito operatore <<.
{
return (os << cli.id << ' ' << cli.ragioneSociale);
}
(3) Con gli stream del C++ otteniamo del codice più robusto. Infatti, in caso di errore, ci viene sollevata un'eccezione. Questa è una novità introdotta recentemente e, per questo, non viene automaticamente attivata (per mantenere compatibilità con le versioni precedenti degli stream). Così dobbiamo attivarla esplicitamente. Per esempio:
myfile.exceptions(ios::badbit | ios::failbit);in questo modo richiediamo che venga sollevata un'eccezione in caso di errore. All'interno di ios_base<> troviamo alcuni importanti data member che ci indicano lo stato dello stream:
- badbit, lo stream è corrotto
- eofbit, raggiunto end-of-file
- failbit, la prossima operazione fallirà
- goodbit, non vi sono errori
cin.exceptions(ios::eofbit);Gestendo l'eccezione std::ios_base::failure, oppure std::exception possiamo essere notificati se qualcosa dovesse andare storto. Per esempio:
ifstream file;
file.exceptions(ios::badbit | ios::failbit);
try {
file.open("pippo.dat");
}
catch (std::ios_base::failure& e)
{
ShowMessage("Can't Open File");
}
catch (std::exception& e)
{
ShowMessage("Eccezione standard library C++");
}