Newsgroup: it.comp.lang.c++
Titolo: [VC++] try-catch e apertura di un file (metodo di una classe)

Ciao a tutti,
sto studiando il C++ (provengo dal C) e sto cercando di entrare
nell'ottica OOP.
Il compilatore è specificato tra parentesi quadre nell'oggetto, ovvero
Visual C++.
Sto cercando di scrivere un parser XML (proprio minimale tanto mi
interessa solo l'implementazione non il risultato)
e ho quindi iniziato dichiarando la classe XMLParser come segue nel
file XMLParser.h:
#include <iostream>
#include <string>
#include <fstream>
class XMLParser {
private:
	std::ifstream _sourceFile;
public:
	XMLParser(char *fileName);
	~XMLParser(void);
};
Come si nota attualmente la classe ha giusto i metodi distruttore e
costruttore. Niente di più.
Ho quindi definito la classe nel file XMLParser.cpp cosi:
#include "XMLParser.h"
XMLParser::XMLParser(char *fileName)
{
	this->_sourceFile.exceptions(std::ifstream::failbit);
	try {
		this->_sourceFile.open(fileName);
	}
	catch(std::ifstream::failure e) {
		std::cout << "Exception opening the file `" << fileName << "'" <<
std::endl;
	}
}
XMLParser::~XMLParser(void)
{
	this->_sourceFile.close();
}
#ifndef NDEBUG
int main()
{
	XMLParser test("text.xml");
	system("pause");
	return(0);
}
#endif /*NDEBUG*/
Cercavo di usare gli statement try e catch per gestire una eventuale
eccezione nell'apertura del file, ma quando eseguo il debug il codice
viene compilato a dovere ma ricevo un errore a runtime dopo la system
call per "bloccare" il terminale. Di seguito l'output del debugger:
[parte tagliata... descrive le librerie caricate]
'XMLParserClass.exe': caricato 'C:\Windows\winsxs
\x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.21022.8_none_96748342450f6aa2\msvcr90d.dll',
Simboli caricati.
Eccezione first-chance a 0x75739617 in XMLParserClass.exe: Eccezione
di Microsoft C++: std::ios_base::failure nella posizione di memoria
0x0026fa58..
'XMLParserClass.exe': caricato 'C:\Windows\System32\apphelp.dll'
Eccezione first-chance a 0x75739617 in XMLParserClass.exe: Eccezione
di Microsoft C++: std::ios_base::failure nella posizione di memoria
0x0026faa4..
Eccezione non gestita a 0x75739617 in XMLParserClass.exe: Eccezione di
Microsoft C++: std::ios_base::failure nella posizione di memoria
0x0026faa4..
Suppongo che il problema sia quindi nello statement catch, ma il tutto
è basato sull'esempio presente sul sito cplusplus (http://
www.cplusplus.com/reference/iostream/ios/exceptions/
)
Ho letto la documentazione relativa alle flag da usare per dichiarare
le "exceptions" e credo di necessitare solo di ifstream::failbit, ma
ho provato anche con badbit.
Cosa sbaglio? (se potete spiegarmelo anzichè darmi solo la correzione
mi sarebbe utile per i futuri casi).
PS. lo style del codice riguardo la nomenclatura l'ho studiata su un
sito reperibile tramite google, mentre il "code styling" è eredità
dell'esperienza col C. Dovrei essere a conoscenza di qualche altra
convenzione utile?
Grazie mille, buona serata a tutti.

A A ha scritto:

Il file test.xml esiste?
Il messaggio "Exception opening the file..." viene visualizzato?
La system("pause") viene eseguita?
I messaggi che riporti vengono visualizzati dopo che hai premuto un 
tasto o prima?
E.


No il file non esiste (dato che sto provando a gestire l'eccezione).
Il messaggio viene visualizzato correttamente e di seguito il classico
avviso di windows che dice di premere un tasto (merito della
system("pause")).
L'errore avviene esattamente quando premo un qualunque tasto per
terminare l'esecuzione.


Mi ripeto per aggiungere che ho aggirato l'eccezione cosi facendo:
XMLParser::XMLParser(char *fileName)
{
	try {
		this->_sourceFile.open(fileName);
		if(this->_sourceFile == false)
			throw "cannot open the file.";
	}
	catch(char *error) {
		std::cout << "`" << fileName << "': " << error << std::endl;
		exit(EXIT_FAILURE);
	}
}
Comunque mi piacerebbe sapere ancora cosa non funziona nel precedente
metodo... il throw è necessario? (ricordo che  quel sistema è presente
sul sito cplusplus)

 terminare l'esecuzione.
Sospetto allora che tu non possa chiamare close() su un ifstream che non 
è stato aperto. Togli quella riga dal distruttore che è inutile e, 
forse, dannosa. Il distruttore dell'ifstream si preoccuperà di chiudere 
il file, se necessario.
E.

>>> costruttore. Niente di pi�.

Questo conferma la mia ipotesi. Chiamando exit le variabili automatiche 
non vengono distrutte.
E.

 E.
Uh già, non ci avevo pensato affatto che potesse dipendere dal
distruttore. Devo assolutamente imparare ad usare il debugger di VC++,
infatti l'unico messaggio che riuscivo (e tutt'ora riesco) a ricavare
riguarda l'eccezione non gestita nella memoria :s
Per tenere traccia delle funzioni in esecuzione ho pensato di definire
una funzione che stampi dei messaggi di debug in questo modo sarprò
sempre qual'è l'ultima istruzione prima del crash :-)
Riguardo il lasciar chiudere lo stream alla classe ifstream non posso,
infatti utilizzando lo stream nel main la classe verrebbe distrutta
alla fine del programma e per tutta la sua esecuzione avrei uno stream
input aperto senza alcuna necessità, l'importante è comunque risolvere
i problemi :-)
Grazie mille per il tempo dedicato, buona notte.

 input aperto senza alcuna necessità, 
Per questo ci sono diverse soluzioni. Innanzitutto bisogna capire se il 
tuo XMLParser può aprire più files in sequenza e quindi se ha senso 
mantenere l'XMLParser quando chiudi il file. Se la risposta fosse 
negativa, basta che mantieni in vita l'XMLParser il minimo possibile. 
Questo lo ottieni dichiarando la variabile nel blocco minimale in cui la 
utilizzi.
In caso contrario sarà nececessario che l'XMLParser sia in grado di 
sapere se l'ifstream è stato collegato ad un file oppure no. Sicuramente 
l'ifstream ha un metodo per rispondere a questa domanda. In alternativa 
potresti allocare l'ifstream dinamicamente quando apri il file. Dunque 
useresti new per aprire il file e delete per chiuderlo. Dopo il delete 
metti a zero il puntatore, e questo ti mantiene memoria del fatto che il 
file in quel momento è chiuso.
E.

 E.
La reference non dice da nessuna parte che il distruttore provvede a
chidere il file, invece il distruttore della classe XMLParser dovrebbe
controllare che il file è aperto prima di invocare close.
Secondo me con:
XMLParser::~XMLParser(void)
{
  if(this->_sourceFile.is_open())
  {
    _sourceFile.close();
  }
}
dovrebbe risolvere....

 dovrebbe risolvere....
In fatti è la mia soluzione, controllo lo stato dello stream e se
aperto lo chiudo.
Dalla doc sulla classe istream:
       "Note that it does not destroy nor performs any operations on
the associated streambuf object."
Questo credo avvalori quanto detto da Michelangelo.
Grazie mille ad entrambi =)
Buona giornata.

 chidere il file, 
Ah, può darsi. Però sono quasi certo che se il file lo passi al 
costruttore, come in
  std::ifstream if(filename);
allora il distruttore lo chiude. La cosa avrebbe comunque il suo perché. 
Però in questo caso non andrebbe bene, perché si genererebbe una 
eccezione durante l'inizializzazione della classe... cosa che è meglio 
evitare...
E.

 chidere il file
A quale reference ti riferisci?
Lo standard (vedere 27.8.1 e seguenti) specifica che il file viene 
chiuso dal distruttore.
Ciao.

 E.
typedef basic_ifstream<char> ifstream;
basic_ifstream() : __istream_type(), _M_filebuf()
{ this->init(&_M_filebuf); }
explicit
basic_ifstream(const char* __s, ios_base::openmode __mode =
ios_base::in) : __istream_type(), _M_filebuf()
{
  this->init(&_M_filebuf);
  this->open(__s, __mode);
}
~basic_ifstream()
{ }
il distruttore non fa nulla... devi chiamare esplicitamente il metodo
close() che tu passi il nome del file nel costruttore o che tu usi il
metodo open.

 metodo open.
finito ora di leggere i sorgenti effettivamente viene chiuso ma dal
distruttore del filebuf interno che va out of scope alla chiusura della
classe quindi si effettivamente il file viene chiuso


finito ora di leggere i sorgenti (ISO C++ 14882: 27.8  File-based
streams) in riferimento al gcc il file viene chiuso dal distruttore del
filebuf interno che va fuori dallo scope nel momento in cui la classe
viene distrutta...
/**
  *  @brief  The destructor does nothing.
  *
  *  The file is closed by the filebuf object, not the formatting
  *  stream.
  */
  ~basic_ifstream()
  { }
mea culpa, in realtà non avendo sottomano un reference attendibile avevo
fatto un grep e visto il distruttore vuoto ...
ora mi sono letto tutto il file ......
che usi come riferimento?
(io mi sono fossilizzato sull'uso delle qt, e le uso ormai per tutto
file,network etc... più facile che ultimamente abbia usato un QFile che
non la libreria standard.)

Ho cercato per lo standard di cui parlate e ho trovato questo:
http://www-d0.fnal.gov/~dladams/cxx_standard.pdf
Sembra molto interessante e credo proprio che lo userò come
riferimento per imparare di più sul C++. Avrebbe senso leggerlo per
intero o mi consigliate di leggere le varie sezioni mano a mano che ne
avrò bisogno? (visto che è lunghissimo).
Grazie :)

 Grazie :)
io mi sono sempre rifatto 
cplusplus.com
 ma solo ed esclusivamente quando
ne avevo bisogno.
molti molti anni fa... ho letto thinking in c++ mentre ultimamente sto
leggendo a scappa tempo "Programming -- Principles and Practice Using C++"

 leggendo a scappa tempo "Programming -- Principles and Practice Using C++"
Mi intriga "Thinking in C++", proverò a cercarlo. Io intanto mi baso
oltre che su cplusplus, su msdn (per le estensioni ms, anche se
compilo sempre con l'opzione /Za abilitata -disabilita le estensioni
microsoft-), e sulla documentazione C++ presente sul sito
http://www.java2s.com/Code/Cpp/CatalogCpp.htm
 e su quello della IBM.
Ciao.

 Ciao.
io sono un utente linux e uso il gcc, a parte 
cplusplus.com
 spesso e
volentieri un occhiata agli header mi da un buon aiuto.

 volentieri un occhiata agli header mi da un buon aiuto.
Prenderò esempio, tenendo presente di non dover scambiare qualche
estensione proprietaria per uno standard :P

 
guarda non voglio fare pubblicità pro_open ma di engine 3d ce ne sono
almeno due:
* irrlicht
* ogre3d
di veramente ottimi che possono renderizzare sia su opengl sia su
directx stando ad un livello di astrazione più alto.
per il resto openal e sdl fanno un buon lavoro su audio, 2d e user input.
Ovviamente usa la piattaforma che preferisci io lavoro su php/java/c++
sui server linux ormai dal 1999 e trovo comodo utilizzare questo sistema
anche sul desktop.
per quanto riguarda lo standard io compilo con:
g++ -Wall -ansi -pedantic
Michelangelo


wrote:

Concordo con te, soprattutto riguardo OGRE che ritengo davvero
eccezionale, sia per com'è scritto (a mio modestissimo parere) che è
ancora meglio di Irrlicht che per il risultato finale esposto sui
rispettivi siti ufficiali. Dato che, la maggior parte dei programmi
professionali, sebbene l'ultima tendenza sia di tenere in
considerazione anche linux, sono per piattaforma Windows. (e poi
quante ditte sono disposte ad assumere uno che non sà proprio nulla di
Windows? -esclusa la Linux Foundation :D-).
Linux lo trovo più "semplice" da programmare, nel senso che grazie a
gcc basta poco per linkare librerie, ottenere questo o quello mentre
con lo strumento grafico di VC++ mi sento confuso -ma ovviamente è per
una mia carenza da colmare-. Ho letto su internet di un certo plugin
che permette di compilare da Visual Studio con gcc installato su una
macchina linux, ma non ho mai trovato niente del genere. Al più uso
SSH, un punto a favore di Windows è l'Intellisense di Visual Studio,
eccezionale e incomparabile con gli altri IDE che ho provato
(code::blocks, anjuta, quello di kde -non ricordo il nome, forse
kdevelop- e tutti quelli C/C++ presenti su un sito reperibile su
google con "IDE linux").
Il mio scopo è quello di avere padronanza di entrambi i sistemi
operativi, ovviamente se si chiede un programma di networking ad alte
prestazioni penso subito a linux (o su windows IOCP).
Per quanto concerne a Linux come desktop, beh si. Lo trovo
perfettamente intercambiabile con Windows, a meno che non si voglia
giocare qualche titolo noto o usare qualche software professionale (e
no, non ritengo che wine sia impeccabile come dicono i fanatici :p).
Detto questo, buona serata!

 che usi come riferimento?
Generalmente faccio qualche ricerca in Internet e nel caso di dubbi 
consulto lo standard stesso, che è la fonte maggiormente autorevole, 
anche se non sempre di facile consultazione.
Ciao

 Detto questo, buona serata!
altrettante