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

Gérer une exception au sein d'une fonction..

8 réponses
Avatar
Xavier
Bonjour,
Je débute et j'ai un peu de mal a gérer une exception...J'aimerais faire
renvoyer un résultat ou un code d'erreur a la fonction si le calcul échoue.
Je pourrais renvoyer le résultat dans un argument par réference... mais
compte tenu de mes besoins cela suffit. Le code d'erreur que ma fonction
doit renvoyer est -1 en cas d'échec. Je prend l'exemple de la fonction
suivante:

double Division(double a, double b)
{
double Tmp = -1;
try
{
Tmp = a/b;
}
catch(...)
{
Tmp = -1.0;
}
return(Tmp);
}

dans la console
cout << Division(3, 2) << endl renvoie 1.5
cout << Division(3, 0) << endl renvoie 1.#INF

Pourquoi ne puis je pas affecter la valeur -1 a Tmp dans le bloc catch?..
Merci pour tout éclaircissement.
Xavier

8 réponses

Avatar
Sylvain
Xavier wrote on 03/04/2007 15:43:

double Division(double a, double b)
{
double Tmp = -1;
try {
Tmp = a/b;
}
catch(...){
Tmp = -1.0;
}
return(Tmp);
}

dans la console
cout << Division(3, 2) << endl renvoie 1.5
cout << Division(3, 0) << endl renvoie 1.#INF

Pourquoi ne puis je pas affecter la valeur -1 a Tmp dans le bloc catch?..


parce que le code n'entre PAS dans le catch (le coproc arith. ne lève
pas d'exception tout seul, même si ...)
une exécution en debug pas à pas l'aurait montré.

Sylvain.

Avatar
Mathias Gaunard
Bonjour,
Je débute et j'ai un peu de mal a gérer une exception...

try
{
Tmp = a/b;
}


Aucune exception n'est jamais levée dans ton bloc try.
Une exception est levée par l'instruction throw et par celle-ci uniquement.

double Division(double a, double b)
{
if(b != 0.0) // éventuellement à affiner car ce sont des doubles?
return a/b;

return -1.0;
}

Après, je ne trouve pas cela particulièrement pertinent de définir x/0
comme étant -1...
Du coup, toute division ayant pour résultat -1 est considérée comme une
erreur : super.

En fait pour ton problème, tu as trois solutions : utiliser le fait que
les doubles ont des représentations particulières pour les résultats
invalides, lever une exception en cas de division par zéro, ou tout
simplement te débrouiller pour que la division par zéro n'arrive jamais,
étant plus une erreur de programmation qu'autre chose.


Pourquoi ne puis je pas affecter la valeur -1 a Tmp dans le bloc catch?..


Parce que tu ne rentres jamais dans ce bloc ?

Avatar
Xavier
Merci a tous deux pour vos réponses. Je crois que j'ai pas du comprendre
grand chose a la génération/réception d'une exeption (je pensais qu'une
exception était levé par une erreur qui renvoyait alors vers le bloc
catch...).
Bon je sais que l'exemple Division par zero n'etait pas judicieux (il faut
le prendre pour un exemple pour illustrer le fonctionnement de ma fonction).
Pour tout dire la fonction qui me pose "probleme" est un peu plus complexe
(une dizaine d'argument que l'utilisateur) et pour ne pas gérer les
arguments entrants avec des if (ce que je ferais quand même a terme), je
voulais pouvoir récuperer un résultat sans faire planter le systeme...
Je vais me replonger dans les exceptions ...
Xavier
Avatar
Sylvain
Xavier wrote on 03/04/2007 18:28:
Merci a tous deux pour vos réponses. Je crois que j'ai pas du comprendre
grand chose a la génération/réception d'une exeption (je pensais qu'une
exception était levé par une erreur qui renvoyait alors vers le bloc
catch...).


ton code gère correctement la réception d'exception mais pas la levée.

aucune opération élémentaire ne génère elle-même une exception, c'est le
code que tu écris, ou les librairies utilisées, qui lève explicitement
une exception.

note également que (quasiment) tout peux servir d'arguments d'exception,
selon ce que tu lèves, ou ce que des libs tierces lèvent, tu devras
fournir les handlers (récepteurs) d'exception correspondant.

au passage, les exceptions peuvent bien surs être chainée, sans en
répercutant l'argument reçu (syntaxe "throw") sans en levant une
nouvelle exception.

exemple:

double Division(double a, double b){
try {
try {
if (b == 1.0)
throw "ça va pas changer grand chose";
if (b == 0.0)
throw (double) -1.0;
return a / b;
}
catch (const char* msg){
cout << msg << endl;
throw (double) a;
}
catch (double value){
throw; // relève une exception avec value
}
}
catch (double resultCode){
return resultCode;
}
}

Sylvain.

Avatar
Xavier
Merci sylvain pour tes explications. Je commence a saisir la logique. Je
crois que je dois encore approfondir pour saisir tout l'interet des
exceptions. Mais les brumes commencent a se lever..
note également que (quasiment) tout peux servir d'arguments d'exception,
selon ce que tu lèves, ou ce que des libs tierces lèvent, tu devras
fournir les handlers (récepteurs) d'exception correspondant.

au passage, les exceptions peuvent bien surs être chainée, sans en
répercutant l'argument reçu (syntaxe "throw") sans en levant une nouvelle
exception.

exemple:

double Division(double a, double b){
try {
try {
if (b == 1.0)
throw "ça va pas changer grand chose";
if (b == 0.0)
throw (double) -1.0;
return a / b;
}
catch (const char* msg){
cout << msg << endl;
throw (double) a;
}
catch (double value){
throw; // relève une exception avec value
Je ne comprend pas bien ce que fait le throw ici (sans argument) ?


}
}
catch (double resultCode){
return resultCode;
}
}


Avatar
Sylvain
Xavier wrote on 03/04/2007 19:23:

double Division(double a, double b){
try {
try {
if (b == 0.0)
lève une exception ""de type"" double


(je n'aime pas cette formule mais à défaut)
throw (double) -1.0;
return a / b;
}
catch (double value){
on attrape ici puisque ""l'on a lancé"" un double


et on "re-throw" l'argument (donc un double valant 'value')
throw; // relève une exception avec value


Je ne comprend pas bien ce que fait le throw ici (sans argument) ?

}
}
catch (double resultCode){
le "throw" nous amène ici puisque un ""double a été lancé""


return resultCode;
}
}




re-thrower (ou "throw" sans argument) peut être utile pour faire le
ménage en cascade, par exemple:

Bar* bar = null;

try {
bar = new Bar();
if (!bar->f())
throw "f is not verified"; // jump to handler1

Foo* foo = null;
try {
foo = new Foo();
if (!foo->g())
throw "g is not verified"; // jump to handler2
}
catch (...){ // handler2, catch all exceptions
if (foo)
delete foo;
// cascade l'exception (quelle que soit puisque "...")
throw; // follow clean-up, jump to handler1
}
}
catch (const char* reason){ // handler1
if (bar)
delete bar;
return errorCode;
}

(la gestion des allocations ne sert qu'à illustrer les exceptions, elle
ne se justifie pas en soi).

Sylvain.


Avatar
Xavier
Merci pour l'explication Sylvain. (j'aurai pu potasser un peu la littérature
pour le "throw;")
Xavier
"Sylvain" a écrit dans le message de news:
4612a5d4$0$27399$
Xavier wrote on 03/04/2007 19:23:

double Division(double a, double b){
try {
try {
if (b == 0.0)
lève une exception ""de type"" double


(je n'aime pas cette formule mais à défaut)
throw (double) -1.0;
return a / b;
}
catch (double value){
on attrape ici puisque ""l'on a lancé"" un double


et on "re-throw" l'argument (donc un double valant 'value')
throw; // relève une exception avec value


Je ne comprend pas bien ce que fait le throw ici (sans argument) ?

}
}
catch (double resultCode){
le "throw" nous amène ici puisque un ""double a été lancé""


return resultCode;
}
}




re-thrower (ou "throw" sans argument) peut être utile pour faire le ménage
en cascade, par exemple:

Bar* bar = null;

try {
bar = new Bar();
if (!bar->f())
throw "f is not verified"; // jump to handler1

Foo* foo = null;
try {
foo = new Foo();
if (!foo->g())
throw "g is not verified"; // jump to handler2
}
catch (...){ // handler2, catch all exceptions
if (foo)
delete foo;
// cascade l'exception (quelle que soit puisque "...")
throw; // follow clean-up, jump to handler1
}
}
catch (const char* reason){ // handler1
if (bar)
delete bar;
return errorCode;
}

(la gestion des allocations ne sert qu'à illustrer les exceptions, elle ne
se justifie pas en soi).

Sylvain.




Avatar
James Kanze
On Apr 3, 4:29 pm, Mathias Gaunard wrote:

Je débute et j'ai un peu de mal a gérer une exception...
try
{
Tmp = a/b;
}


Aucune exception n'est jamais levée dans ton bloc try.


Ça, on ne peut pas le dire non plus. Il a une division par 0 ;
c'est un comportement indéfini, et donc, on ne sait pas ce qui
va se passer.

Sur des processeurs qui implémente les flottants IEEE, la
division par 0 a un comportement défini, qui est de renvoyer la
valeur infini (et non de lever une exception). Sur les autres
processeurs que j'ai eu l'occasion d'essayer (et dans le cas de
l'arithmetique des entiers sur tous les processeurs), la
division par 0 provoque l'arrêt du programme : en fait, il lève
un « signal » (non une exception) dont le traitement par
défaut est de générer un core dump et de terminer le programme.

Une exception est levée par l'instruction throw et par
celle-ci uniquement.


Dans le cas d'un comportement indéfini, tout est possible. Y
compris une exception.

double Division(double a, double b)
{
if(b != 0.0) // éventuellement à affiner car ce sont des doubl es?
return a/b;

return -1.0;
}

Après, je ne trouve pas cela particulièrement pertinent de définir x/0
comme étant -1...


C'était sans doute à titre d'exemple, et que les conditions
d'erreur sont plus complexe dans son code réel.

--
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