OVH Cloud OVH Cloud

est-ce une bonne astuce?

36 réponses
Avatar
dark poulpo
alors voila:

imaginons ce cas


void func()
{

ouvre(a);
ouvre(b);

test();
if (error()) { ferme(a); ferme(b); return; } // je le met sur un ligne pour
visualiser les 2 cas plus simplement

testa();
if (error()) { ferme(a); ferme(b); return; }

testb();
if (error()) { ferme(a); ferme(b); return; }

testc();
if (error()) { ferme(a); ferme(b); return; }

....
....

ferme(a);
ferme(b);
return;
}
//////////////////////////////
par
/////////////////////////////

void func()
{

ouvre(a);
ouvre(b);

while(1)
{
test();
if (error()) break;

testa();
if (error()) break;

testb();
if (error()) break;

testc();
if (error()) break;

....
....
break;
}
ferme(a);
ferme(b);
return;
}

qu'en pensez-vous?

6 réponses

1 2 3 4
Avatar
Andre Heinen
On Sun, 1 Aug 2004 16:58:44 +0200, "dark poulpo"
wrote:

merci pour vos reponses,
il se trouve que les testes error() sont des fonctions a moi qui
verifientleta dune variable, doisje faire une declanchement d'exception dans
ce cas la?
pour moi, les exceptions sont la pour eviter certain plantage/des erreurs
syteme, dans mon ca ca n'est pas pour eviter un plantage. donc est-ce
vraiment utile?


Les exceptions ne sont pas seulement là pour les erreurs système,
mais aussi pour les erreurs de l'application.

Si j'ai bien compris ton code, tu fais quelque chose de ce genre:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

bool erreur;

void ouvrir(ifstream& fichier, string nom) {
fichier.open(nom.c_str());
}

void fermer(ifstream& fichier) {
fichier.close();
}

void tester(const ifstream& fichier) {
if (fichier) erreur = false;
else erreur = true;
}

void lireFichier(string nom) {
ifstream fichier;
ouvrir(fichier, nom);
tester(fichier);
if (erreur) {
fermer(fichier);
return;
}
cout << "utilisation du fichier icin";
fermer(fichier);
}

int main() {
lireFichier("monfichier.txt");
}

//=======================================
Alors que tu aurais pu écrire:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Erreur {};

void ouvrir(ifstream& fichier, string nom) {
fichier.open(nom.c_str());
if ( ! fichier) throw Erreur();
}

void lireFichier(string nom) {
ifstream fichier;
ouvrir(fichier, nom);
cout << "utilisation du fichier icin";
}

int main() {
try {
lireFichier("monfichier.txt");
} catch(Erreur&) {
cout << "une erreur s'est produiten";
}
}

//=======================================
Dans le premier cas, chaque fonction appelante doit vérifier si
les fonctions appelées ont rencontré un problème, puis
retransmettre l'erreur éventuelle à leur propre appelante.

Dans le deuxième cas, on ne s'occupe de rien. On ne met pas de
code pour transmettre les erreurs. L'exception revient toute
seule jusqu'à une appelante pouvant gérer l'erreur. On n'a pas
non plus besoin de refermer le fichier, car la classe ifstream
utilise RAII, et son destructeur fermera le fichier quoi qu'il
arrive: fin de fonction, return ou exception.

Dans le premier cas, un problème supplémentaire se pose: comment
transmettre aux appelantes l'information relative à l'erreur?
J'ai utilisé ici une variable globale (pouah), comme ERRNO en C.
On peut aussi demander aux fonctions appelées de retourner un
code d'erreur. Dans les deux cas, tu dois chaque fois penser à
tester la valeur. Tu oublieras tôt ou tard.

Il ne faut pas hésiter à utiliser les exceptions.

Note: dans le cas de ifstream il n'est pas nécessaire d'utiliser
open(): il existe un constructeur qui ouvre le fichier dès la
création de l'instance:

void lireFichier(string nom) {
ifstream fichier(nom.c_str());
if ( ! fichier) throw Erreur();
cout << "utilisation du fichier icin";
}

--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"

Avatar
spam
"Florent 'flure' C." wrote in message news:...
Le Sat, 31 Jul 2004 22:37:09 +0200, dark poulpo a écrit :

qu'en pensez-vous?


Pourquoi pas plutôt ceci :

void func()
{
try {
ouvre(a);
ouvre(b);
test();
} finally {
ferme(a);
ferme(b);
}
}


En C++, ça doit plutôt se coder comme ça :

try {
ouvre(a);
ouvre(b);
test();
}
catch (...) {
ferme(a);
ferme(b);
throw; // relance l'exception plus loin en espérant que
// quelqu'un l'attrape :-P
}
ferme(a);
ferme(b);

Le GROS problème étant d'avoir à répêter deux fois le code (ferme(a);
ferme(b);). Ceci est source d'incohérence (une seule partie est mise à
jour). Proposition de solution : faire une macro (#define ou fonction
appelant ferme(a) et ferme(b)).

@+ Haypo


Avatar
Fabien LE LEZ
On 3 Aug 2004 04:06:54 -0700, (Victor STINNER):

Proposition de solution : faire une macro (#define ou fonction
appelant ferme(a) et ferme(b)).


Mon dieu mon dieu... tu as trouvé la pire des solutions, digne de
l'IOCCC. Les bonnes solutions ont été fournies ailleurs dans ce
thread.


--
;-)

Avatar
Andre Heinen
On 3 Aug 2004 04:06:54 -0700, (Victor STINNER)
wrote:

try {
ouvre(a);
ouvre(b);
test();
}
catch (...) {
ferme(a);
ferme(b);
throw; // relance l'exception plus loin en espérant que
// quelqu'un l'attrape :-P
}
ferme(a);
ferme(b);

Le GROS problème étant d'avoir à répêter deux fois le code (ferme(a);
ferme(b);). Ceci est source d'incohérence (une seule partie est mise à
jour).


Un autre problème est que si ouvre(b) déclenche une exception
sans être parvenue à ouvrir b, une erreur se produira lorsqu'on
exécutera ferme(b). Il vaut mieux utiliser l'idiome RAII: le
destructeur de b sera exécuté si et seulement si b a été
construit.

Proposition de solution : faire une macro


Une quoi? ;-)

--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"

Avatar
drkm
(Victor STINNER) writes:

En C++, ça doit plutôt se coder comme ça :


Non. La manière dont cela se code a été donné à maintes reprises
dans ce fil.

try {
ouvre(a);
ouvre(b);
test();
}
catch (...) {
ferme(a);
ferme(b);
throw; // relance l'exception plus loin en espérant que
// quelqu'un l'attrape :-P
}
ferme(a);
ferme(b);

Le GROS problème étant d'avoir à répêter deux fois le code (ferme(a);
ferme(b);). Ceci est source d'incohérence (une seule partie est mise à
jour). Proposition de solution : faire une macro (#define ou fonction
appelant ferme(a) et ferme(b)).


La solution idiomatique gère très bien ce genre de choses. En fait,
le bout de code ci-dessus donne deux chemins d'exécution possibles
pour sortir de la fonction. Mais il peut y en avoir plusieurs, s'il y
a plusieurs throws, plusieurs appels à des fonctions lançant des
exceptions, plusieurs returns, etc. Tout cela est pris en compte par
RAII.

--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html

Avatar
Luc Hermitte
Patrick Mézard wrote in
news:ceh0gh$i11$:
[SNIP]
Tu peux chercher RAII (Resource Aquisition Is Initialization) dans les
archives du groupe ou sur n'importe quel autre newsgroup/forum dédié
au C++. C'est l'idiome courant en pour réaliser ça.


Il y a un article d'Andrei Alexandrescu et John Torjo (je crois) sur les
scope guard dans les archives du C/C++ Users Journal (http://www.cuj.com)
qui traite justement de cela.

--
Luc Hermitte <hermitte at free.fr>
FAQ de <news:fr.comp.lang.c++> :
<http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/>
Dejanews : <http://groups.google.com/advanced_group_search>

1 2 3 4