Sections

FG&A s.r.l.

Personal tools
You are here: Home Articoli Gli stream del C++ e le eccezioni
Document Actions

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*/)
{
ofstream myfile("pippo.dat");
while (!myfile.eof())
; // Processo i dati
}
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.

(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;
myfile << cli << endl;
L'operatore<< sarebbe definito più o meno così:
    /*friend*/ ostream& operator<<(ostream& os, const Cliente& x)
{
return (os << cli.id << ' ' << cli.ragioneSociale);
}
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 <<.

(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
Il metodo exceptions() ci permette di indicare in quali casi deve essere sollevata un'eccezione. Così, se volessimo che ci venisse sollevata un'eccezione a fronte di end-of-file su "cin" (anche se poco sensato), potremmo scrivere:
    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++");
}