Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Erreur contre exception : la solution de normand

13 réponses
Avatar
Jean-Marc Desperrier
Salut,

En regardant quelques discussion intéressante sur la meilleure façon de
gérer les erreurs dans un programme C++ ici :
http://damienkatz.net/2006/04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à choisir au
moment de l'écriture d'une fonction si elle sera gérée avce un code
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?

Illustration à la suite :
include <iostream>

class ErrorValue {
int rv;
bool checked;

public:
ErrorValue(int v): rv(v), checked(false) {}
~ErrorValue() {if (checked==false) throw *this;}
operator int() {checked=true;return rv;}
};

ErrorValue test1 () {
return ErrorValue(1);
}

ErrorValue test2 () {
return ErrorValue(2);
}

int main(int argc, char * argv[]) {
try {
int rc = test1();
std::cout << "Return ErrorValue of first test is "
<< rc << "\n";
test2();
} catch (ErrorValue &ev) {
std::cout << "ErrorValue catched is "
<< ev << "\n" ;
}
}

PS : Avec cette écriture, il y a quand même un petit piège potentiel,
qu'on retrouve dans ma première version avec "catch (ErrorValue ev)" où
le programme ne se terminait pas très bien, pe que "throw rv" serait
plus raisonnable ou bien contruire un type qui n'est pas vérifié pour ce
throw.

10 réponses

1 2
Avatar
Michael DOUBEZ
Salut,

En regardant quelques discussion intéressante sur la meilleure façon de
gérer les erreurs dans un programme C++ ici :
http://damienkatz.net/2006/04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à choisir au
moment de l'écriture d'une fonction si elle sera gérée avce un code
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?
[snip]


Au lieu de jeter l'exception dans un destructeur, je préférerais deux
méthodes me permettant de choisir l'une ou l'autre solution (Si
l'utilisateur ne check pas le retour de la fonction; il a le droit de ne
pas s'y intéresser.) et je préférerais ne pas lancer une exception
systématiquement.
Sinon, jeter une exception dans un destructeur pose la question de
savoir ce qu'il advient de la mémoire (comment est implémenté le delete)
donc il y une forte chance que ce ne soit pas portable à moins de
l'overloader.


Exemple modifié:
class ErrorValue {
int rv;
bool throwme;

public:
ErrorValue(int v,bool túlse): rv(v), throwme(t) {}
int throwValue()const {if (throwme) throw *this; return rv;}
int getValue()const {return rv;}
//operator int()const {return rv;}
};

ErrorValue test1 () {
return ErrorValue(1,true);//error and throw it
}

ErrorValue test2 () {
return ErrorValue(2,true);//error and throw it
}

ErrorValue test2 () {
return ErrorValue(0,false);//not an error or don't throw it
}


int main(int argc, char * argv[]) {
try {
int rc = test1().getValue();
std::cout << "Return ErrorValue of first test is "
<< rc << "n";


test3().throwValue();

test2();//ne check pas le retour dans ce cas

test2().throwValue();//throw l'erreur dans ce cas
} catch (ErrorValue &ev) {
std::cout << "ErrorValue catched is "
<< ev << "n" ;
}
}

Avatar
adebaene
On 11 déc, 11:39, Jean-Marc Desperrier wrote:
Salut,

En regardant quelques discussion intéressante sur la meilleure façon de
gérer les erreurs dans un programme C++ ici :http://damienkatz.net/2006 /04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à choisir au
moment de l'écriture d'une fonction si elle sera gérée avce un code
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?

Illustration à la suite :
<snip>


Indépendamment du mécanisme qui permet de lever une exception dans le
destructeur, je vois un gros défaut à cette approche : Le code
d'erreur lui-même est encore codé sur un int, plutôt que de profiter
du typage des exceptions ainsi que d'exceptions "riches" qui
contiennent d'avantage de contexte sur la cause/le lieu, etc... de
l'erreur.
Pour adapter du code existant, pourquoi pas, mais si c'est pour écrire
du code neuf et qu'on décide d'utiliser les exceptions, autant les
utiliser à fond en profitant de la richesse descriptive qu'elles
peuvent fournir.

Arnaud

Avatar
Marc Boyer
Le 11-12-2006, Jean-Marc Desperrier a écrit :
Salut,

En regardant quelques discussion intéressante sur la meilleure façon de
gérer les erreurs dans un programme C++ ici :
http://damienkatz.net/2006/04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à choisir au
moment de l'écriture d'une fonction si elle sera gérée avce un code
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?


C'est peut-etre interessant. Bon, faudrait affiner, pouvoir
ignorer certaines codes de retour (tous les codes de retour ne sont
pas des erreurs), mais c'est une base.
Après, faudrait aussi vérfier dans la norme la possibilité de lancer
une exception dans un destructeur.


Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)

Avatar
Jean-Marc Desperrier
Marc Boyer wrote:
Après, faudrait aussi vérfier dans la norme la possibilité de lancer
une exception dans un destructeur.


'Fectivement, bien que cela ne soit totalement interdit ça peut poser de
gros problèmes :-), cd http://www.gotw.ca/gotw/047.htm pour les détails

Avatar
Marc Boyer
Le 11-12-2006, Jean-Marc Desperrier a écrit :
Marc Boyer wrote:
Après, faudrait aussi vérfier dans la norme la possibilité de lancer
une exception dans un destructeur.


'Fectivement, bien que cela ne soit totalement interdit ça peut poser de
gros problèmes :-), cd http://www.gotw.ca/gotw/047.htm pour les détails


Ceci dit, c'est peut-etre un des rares cas ou le uncaught_exception
est peut-être utile.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)


Avatar
Laurent Deniau
Jean-Marc Desperrier wrote:
Salut,

En regardant quelques discussion intéressante sur la meilleure façon de
gérer les erreurs dans un programme C++ ici :
http://damienkatz.net/2006/04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à choisir au
moment de l'écriture d'une fonction si elle sera gérée avce un code
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?

Illustration à la suite :
include <iostream>

class ErrorValue {
int rv;
bool checked;

public:
ErrorValue(int v): rv(v), checked(false) {}
~ErrorValue() {if (checked=úlse) throw *this;}
operator int() {checked=true;return rv;}
};

ErrorValue test1 () {
return ErrorValue(1);
}

ErrorValue test2 () {
return ErrorValue(2);
}

int main(int argc, char * argv[]) {
try {
int rc = test1();
std::cout << "Return ErrorValue of first test is "
<< rc << "n";
test2();
} catch (ErrorValue &ev) {
std::cout << "ErrorValue catched is "
<< ev << "n" ;
}
}

PS : Avec cette écriture, il y a quand même un petit piège potentiel,
qu'on retrouve dans ma première version avec "catch (ErrorValue ev)" où
le programme ne se terminait pas très bien, pe que "throw rv" serait
plus raisonnable ou bien contruire un type qui n'est pas vérifié pour ce
throw.


hormis le fait que cette classe suppose que le code de retour est un
entier, qu'il empeche de cascader les appels et qu'il est facile de lui
faire lever une exception pendant un stack unwinding ou encore de perdre
accidentellement la trace de la derniere erreur. Je pense qu'il serait
aussi utile d'ajouter qqchose comme:

~ErrorValue() {if (checked=úlse && rv!=not_an_error) throw *this;}

Parce que sinon toutes les valeurs de retour se transforment en
exception (pas tres utile). Il n'a pas du etre beaucoup utilise ce code,
non?

a+, ld.

Avatar
James Kanze
Jean-Marc Desperrier wrote:

En regardant quelques discussion intéressante sur la meilleure façon de
gérer les erreurs dans un programme C++ ici :
http://damienkatz.net/2006/04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à choisir au
moment de l'écriture d'une fonction si elle sera gérée avce un code
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?


Il y a eu une discussion recemment sur ce sujet dans
comp.lang.c++.moderated.

Dans l'ensemble, je ne suis pas trop convaincu en ce qui
concerne la possibilité de convertir des codes de retour en
exceptions. Dans la doute, au niveau de la bibliothèque, on se
sert tout bêtement des codes de retour -- c'est assez simple
pour l'utilisateur de les convertir en exceptions, si c'est ce
qu'il veut.

Une alternative, c'est un callback (qui par défaut ne fait rien,
mais qui pourrait lever une exception), ou des options, à peu
près comme les iostream. À une époque, je croyais un callback la
solution idéale, mais je suis un peu revenu de cet avis. Le
problème, c'est le code qui reçoit l'objet d'ailleurs, et qui ne
sait pas à priori comment il signale ses erreurs.

Enfin, je me suis souvent servi d'une classe ReturnCode dans des
applications, mais qui génère un échec d'assertion si l'erreur
n'a pas été testé -- ne pas tester le code de retour, c'est une
erreur dans le programme. Aussi, ma classe Fallible génère un
échec d'assertion si on essaie d'utiliser la valeur si elle
n'est pas valide ; ce n'est pas tout à fait la même chose,
puisqu'on ne détecte pas l'absense de vérification dans le cas
où il n'y a pas d'erreur, mais un bon test doit bien comporter
les cas d'erreur.

Illustration à la suite :
include <iostream>

class ErrorValue {
int rv;
bool checked;

public:
ErrorValue(int v): rv(v), checked(false) {}
~ErrorValue() {if (checked=úlse) throw *this;}
operator int() {checked=true;return rv;}
};


Et le constructeur de copie ? Quand tu fais « return
ErrorValue( n ) », il y a bien conceptuellement une copie,
que le compilateur peut supprimer à titre d'optimisation, mais
qu'il n'est pas obligé de supprimer. Or, après la copie, on
appelle le destructeur sur l'original, sans que tu aies même la
possibilité de le tester.

Et si tu décides exprès d'ignorer l'exception... Le throw dans
le destructeur va aussi faire une copie. Que ce passe-t-il si tu
fais quelque chose du genre :

catch ( ErrorValue const& ) { ... }

sans régarder la valeur elle-même dans le bloc de catch ?

Enfin, il y a le problème qui a déclencher la discussion dans
comp.lang.c++.moderated :

ErrorValue
func()
{
ErrorValue v = doSomething() ;
if ( v ) {
v = doSomethingElse() ;
}
return v ;
}

Si il y a une erreur au rétour de doSomething(), le code de
retour a été vérifié, et donc, même si l'appelant oublie de le
vérifier...

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
James Kanze
Michael DOUBEZ wrote:

En regardant quelques discussion intéressante sur la meilleure faço n de
gérer les erreurs dans un programme C++ ici :
http://damienkatz.net/2006/04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à chois ir au
moment de l'écriture d'une fonction si elle sera gérée avce un co de
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?
[snip]


Au lieu de jeter l'exception dans un destructeur, je préférerais deux
méthodes me permettant de choisir l'une ou l'autre solution (Si
l'utilisateur ne check pas le retour de la fonction; il a le droit de ne
pas s'y intéresser.) et je préférerais ne pas lancer une exception
systématiquement.


Ça me semble préférable aussi. Je n'aime pas l'idée qu'une
erreur se transforme en exception suite à une erreur de codage.

Sinon, jeter une exception dans un destructeur pose la question de
savoir ce qu'il advient de la mémoire (comment est implémenté le de lete)
donc il y une forte chance que ce ne soit pas portable à moins de
l'overloader.


Je ne comprends pas le problème ici. Il n'y a pas de delete. À
la rigueur, il pourrait déclarer un operator delete privé dans
la classe, afin de le garantir, mais dans la pratique, je crois
que la risque qu'un utilisateur fasse de l'allocation dynamique
d'une telle classe est assez faible.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
James Kanze
Marc Boyer wrote:

[...]
Après, faudrait aussi vérfier dans la norme la possibilité de lan cer
une exception dans un destructeur.


C'est permis pas le langage, et je n'ai jamais entendu parler
d'un compilateur où ça fait un problème. Il y a des
restrictions : si le destructeur d'un objet dans une collection
standard lève une exception, c'est un comportement indéfini, par
exemple, et je ne suis pas sûr que le comportement soit
réelement bien défini si le destructeur est appelé dans une
expression de delete, mais ces restrictions ne doivent pas poser
de problème pour l'utilisation qu'il a en vue.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Michael DOUBEZ
Michael DOUBEZ wrote:

En regardant quelques discussion intéressante sur la meilleure façon de
gérer les erreurs dans un programme C++ ici :
http://damienkatz.net/2006/04/error_code_vs_e.html

Je suis tombé sur la proposition suivante pour ne pas avoir à choisir au
moment de l'écriture d'une fonction si elle sera gérée avce un code
d'erreur ou une exception :
"There is a way to let the caller make the decision of code vs.
exception. I wrote a class that can be returned just like an error code,
but it automatically throws an exception if its status isn't checked. It
allowed us to convert an entire library written with an error code
paradigm, to optionally use exceptions instead."

En fait c'est hyper simple à faire, je me demande ce que vous pensez de
cette technique ?
[snip]
Sinon, jeter une exception dans un destructeur pose la question de

savoir ce qu'il advient de la mémoire (comment est implémenté le delete)
donc il y une forte chance que ce ne soit pas portable à moins de
l'overloader.


Je ne comprends pas le problème ici. Il n'y a pas de delete. À
la rigueur, il pourrait déclarer un operator delete privé dans
la classe, afin de le garantir, mais dans la pratique, je crois
que la risque qu'un utilisateur fasse de l'allocation dynamique
d'une telle classe est assez faible.



Effectivement, c'est alloué dans la pile. Il n'y a pas de problème.



1 2