> Il ne modifie pas le parseur, ce sont des combinators qui demande au
> parseur de valider un input en utilisant des combinator de plus bas
> niveau (char ou wchar_t). Et c'est la raison pour laquelle ils ne sont
> pas membre. C'est le parseur qui track ou il en est. Libre ensuite de
> convertir la validation courante en objet (type).
As-tu une reference?
Le nom m'evoque une technique qui est proche, mais
visiblement il y a des details qui different au point que nous ne nous
comprennons pas du tout. En particulier, tu as l'air d'impliquer qu'on
peut avoir des messages d'erreur raisonnables pour une description qui ne
tient pas compte de ca,
alors qu'utilisee de maniere trop naive, la
technique que je connais donne facilement des messages d'erreur
inutilisables, pires que le "syntax error" de yacc car ils ne pointent me me
pas a la fin du prefixe viable le plus long (on peut relativement
facilement arriver a cela, mais c'est quand meme le degre 0 du message
d'erreur).
> Il ne modifie pas le parseur, ce sont des combinators qui demande au
> parseur de valider un input en utilisant des combinator de plus bas
> niveau (char ou wchar_t). Et c'est la raison pour laquelle ils ne sont
> pas membre. C'est le parseur qui track ou il en est. Libre ensuite de
> convertir la validation courante en objet (type).
As-tu une reference?
Le nom m'evoque une technique qui est proche, mais
visiblement il y a des details qui different au point que nous ne nous
comprennons pas du tout. En particulier, tu as l'air d'impliquer qu'on
peut avoir des messages d'erreur raisonnables pour une description qui ne
tient pas compte de ca,
alors qu'utilisee de maniere trop naive, la
technique que je connais donne facilement des messages d'erreur
inutilisables, pires que le "syntax error" de yacc car ils ne pointent me me
pas a la fin du prefixe viable le plus long (on peut relativement
facilement arriver a cela, mais c'est quand meme le degre 0 du message
d'erreur).
> Il ne modifie pas le parseur, ce sont des combinators qui demande au
> parseur de valider un input en utilisant des combinator de plus bas
> niveau (char ou wchar_t). Et c'est la raison pour laquelle ils ne sont
> pas membre. C'est le parseur qui track ou il en est. Libre ensuite de
> convertir la validation courante en objet (type).
As-tu une reference?
Le nom m'evoque une technique qui est proche, mais
visiblement il y a des details qui different au point que nous ne nous
comprennons pas du tout. En particulier, tu as l'air d'impliquer qu'on
peut avoir des messages d'erreur raisonnables pour une description qui ne
tient pas compte de ca,
alors qu'utilisee de maniere trop naive, la
technique que je connais donne facilement des messages d'erreur
inutilisables, pires que le "syntax error" de yacc car ils ne pointent me me
pas a la fin du prefixe viable le plus long (on peut relativement
facilement arriver a cela, mais c'est quand meme le degre 0 du message
d'erreur).
On 5 juil, 11:41, "Patrick 'Zener' Brunet"
wrote:"Guillaume Gourdin" a écrit dans le message
de news 4a4f3042$0$30992$selon ma (modeste) expérience, les exceptions en C++sont très
largement sous utilisées, et on en reste (me semble t-il) toujours
à la bonne vieille méthode du retour d'un code d'erreur. Je suis
un peu surpris de cet état de fait, les exceptions étant supposées
apporter une gestion plus performantes des erreurs. J'ai dons
quelques questions: est-il vrai que les exceptions sont sous
utilisées? Quels sont vos retours d'expérience? Ou bien y a t'il
une raison plus profonde à la sous-utilisation des exceptions?
En complément aux arguments de Fabien Le Lez, en lisant du code C++
utilisant des exceptions, on voit souvent des choses aussi lourdes
que risquées, qui peuvent donc "discréditer" les exceptions aux
yeux de certains.
Lancer une exception implique de la construire, donc il vaut mieux
que cette partie-là soit garantie.
C'est pour ça qu'il y a la garantie nothrow. Mais dans le cas
général, à moins d'un état grave de manque de mémoire, la
construction des exceptions n'est pas un problème.
Il n'est pas rare de voir des exceptions créées par un new, et
pour faire bonne mesure, on insère tout un tas de diagnostics
dedans sous forme de strings...
C'est du code à la Java.
Tout ça pour traiter un incident tels qu'un échec d'allocation de
mémoire ? Il doit bien y avoir des gens que ça ennuie...
Je prefère une exception à un NULL à vérifier chaque fois.
De toutes
façons, je ne sais pas quoi faire si j'ai plus de mémoire, il y a
peux de chance qu'essayer de nouveau marche. Le mieux est encore de
revenir à un état antérieur qui se prétend capable de gérer la
situation.
Ensuite, comment passe-t-on cette exception (que "throwe"-t-on) ?
Par adresse, référence ou par copie ?
Pour autant que je sache, on ne peux pas lancer par référence.
Un bonne règle est de lancer par valeur et de catcher par référence
pour éviter le slicing.
La copie est plus naturelle, mais elle implique effectivement de
copier tout ça (donc de mouliner intérieurement du new et du
delete).
Je ne comprends pas ce que tu veux dire ici.
Reste à voir ce qu'on en fait à la fin (le catch).
Si le système d'exceptions est bien fait, d'une part on a une
hiérarchie bien claire permettant de cascader les catch
spécifiques et de se passer du catch-all (sauf pour faire un
cleanup intermédiaire suivi d'un rethrow).
Si je catche quelque chose, c'est que j'ai prévu de le traiter et
que personne ne pense pouvoir le faire dans une sosu-couche donc je
sais bien ce que je doit catcher.
Généralement on est bien embêté parce qu'on se tape pour
l'occasion une librairie plus ou moins exotique et on n'a pas trop
le temps de creuser son fonctionnement intime (c'est même ce qu'on
veut éviter - on a la pression bien sûr):
- Pour le détail des causes d'échec possibles, normalement, on
regarde les retours de la fonction appelée, et on fait un switch
avec un default... - Pour une exception, ça peut venir de plus
profond et donc c'est assez obtus. On ne veut pas en oublier une
parce que ça conduit à un plantage et c'est pas vendeur. Et ça
peut arriver par la suite avec une nouvelle version de ladite
librairie. D'où le choix du catch-all équivalent du défault...
Il y a plein de façon d'avoir une bibliothèque mal conçue en dehors
des exceptions.
[...]
D'expérience, souvent on voit un catch-all avec dedans un
printf("oh zut, ça a foiré") suivi de return(ERROR).
Il y a beaucoup de cas où il est difficile de trouver une façon
gracieuse de gérer l'erreur. S'assurer que l'utilisateur n'a pas
perdu de données et lui donner une idée du diagnostique est un
minimum mais souvent c'est déjà pas mal.
[...]
Moi j'aime pas trop les logiciels qui disent "au
secours, j'y arrive pas", de plus je fais dans le process
automatisé, alors souvent il n'y a personne pour lire le message.
Un petit mail à l'administrateur, ça fait toujours plaisir :)
On 5 juil, 11:41, "Patrick 'Zener' Brunet"
<use.link.in.signat...@ddress.invalid> wrote:
"Guillaume Gourdin" <tr...@hotmail.com> a écrit dans le message
de news 4a4f3042$0$30992$426a7...@news.free.fr
selon ma (modeste) expérience, les exceptions en C++sont très
largement sous utilisées, et on en reste (me semble t-il) toujours
à la bonne vieille méthode du retour d'un code d'erreur. Je suis
un peu surpris de cet état de fait, les exceptions étant supposées
apporter une gestion plus performantes des erreurs. J'ai dons
quelques questions: est-il vrai que les exceptions sont sous
utilisées? Quels sont vos retours d'expérience? Ou bien y a t'il
une raison plus profonde à la sous-utilisation des exceptions?
En complément aux arguments de Fabien Le Lez, en lisant du code C++
utilisant des exceptions, on voit souvent des choses aussi lourdes
que risquées, qui peuvent donc "discréditer" les exceptions aux
yeux de certains.
Lancer une exception implique de la construire, donc il vaut mieux
que cette partie-là soit garantie.
C'est pour ça qu'il y a la garantie nothrow. Mais dans le cas
général, à moins d'un état grave de manque de mémoire, la
construction des exceptions n'est pas un problème.
Il n'est pas rare de voir des exceptions créées par un new, et
pour faire bonne mesure, on insère tout un tas de diagnostics
dedans sous forme de strings...
C'est du code à la Java.
Tout ça pour traiter un incident tels qu'un échec d'allocation de
mémoire ? Il doit bien y avoir des gens que ça ennuie...
Je prefère une exception à un NULL à vérifier chaque fois.
De toutes
façons, je ne sais pas quoi faire si j'ai plus de mémoire, il y a
peux de chance qu'essayer de nouveau marche. Le mieux est encore de
revenir à un état antérieur qui se prétend capable de gérer la
situation.
Ensuite, comment passe-t-on cette exception (que "throwe"-t-on) ?
Par adresse, référence ou par copie ?
Pour autant que je sache, on ne peux pas lancer par référence.
Un bonne règle est de lancer par valeur et de catcher par référence
pour éviter le slicing.
La copie est plus naturelle, mais elle implique effectivement de
copier tout ça (donc de mouliner intérieurement du new et du
delete).
Je ne comprends pas ce que tu veux dire ici.
Reste à voir ce qu'on en fait à la fin (le catch).
Si le système d'exceptions est bien fait, d'une part on a une
hiérarchie bien claire permettant de cascader les catch
spécifiques et de se passer du catch-all (sauf pour faire un
cleanup intermédiaire suivi d'un rethrow).
Si je catche quelque chose, c'est que j'ai prévu de le traiter et
que personne ne pense pouvoir le faire dans une sosu-couche donc je
sais bien ce que je doit catcher.
Généralement on est bien embêté parce qu'on se tape pour
l'occasion une librairie plus ou moins exotique et on n'a pas trop
le temps de creuser son fonctionnement intime (c'est même ce qu'on
veut éviter - on a la pression bien sûr):
- Pour le détail des causes d'échec possibles, normalement, on
regarde les retours de la fonction appelée, et on fait un switch
avec un default... - Pour une exception, ça peut venir de plus
profond et donc c'est assez obtus. On ne veut pas en oublier une
parce que ça conduit à un plantage et c'est pas vendeur. Et ça
peut arriver par la suite avec une nouvelle version de ladite
librairie. D'où le choix du catch-all équivalent du défault...
Il y a plein de façon d'avoir une bibliothèque mal conçue en dehors
des exceptions.
[...]
D'expérience, souvent on voit un catch-all avec dedans un
printf("oh zut, ça a foiré") suivi de return(ERROR).
Il y a beaucoup de cas où il est difficile de trouver une façon
gracieuse de gérer l'erreur. S'assurer que l'utilisateur n'a pas
perdu de données et lui donner une idée du diagnostique est un
minimum mais souvent c'est déjà pas mal.
[...]
Moi j'aime pas trop les logiciels qui disent "au
secours, j'y arrive pas", de plus je fais dans le process
automatisé, alors souvent il n'y a personne pour lire le message.
Un petit mail à l'administrateur, ça fait toujours plaisir :)
On 5 juil, 11:41, "Patrick 'Zener' Brunet"
wrote:"Guillaume Gourdin" a écrit dans le message
de news 4a4f3042$0$30992$selon ma (modeste) expérience, les exceptions en C++sont très
largement sous utilisées, et on en reste (me semble t-il) toujours
à la bonne vieille méthode du retour d'un code d'erreur. Je suis
un peu surpris de cet état de fait, les exceptions étant supposées
apporter une gestion plus performantes des erreurs. J'ai dons
quelques questions: est-il vrai que les exceptions sont sous
utilisées? Quels sont vos retours d'expérience? Ou bien y a t'il
une raison plus profonde à la sous-utilisation des exceptions?
En complément aux arguments de Fabien Le Lez, en lisant du code C++
utilisant des exceptions, on voit souvent des choses aussi lourdes
que risquées, qui peuvent donc "discréditer" les exceptions aux
yeux de certains.
Lancer une exception implique de la construire, donc il vaut mieux
que cette partie-là soit garantie.
C'est pour ça qu'il y a la garantie nothrow. Mais dans le cas
général, à moins d'un état grave de manque de mémoire, la
construction des exceptions n'est pas un problème.
Il n'est pas rare de voir des exceptions créées par un new, et
pour faire bonne mesure, on insère tout un tas de diagnostics
dedans sous forme de strings...
C'est du code à la Java.
Tout ça pour traiter un incident tels qu'un échec d'allocation de
mémoire ? Il doit bien y avoir des gens que ça ennuie...
Je prefère une exception à un NULL à vérifier chaque fois.
De toutes
façons, je ne sais pas quoi faire si j'ai plus de mémoire, il y a
peux de chance qu'essayer de nouveau marche. Le mieux est encore de
revenir à un état antérieur qui se prétend capable de gérer la
situation.
Ensuite, comment passe-t-on cette exception (que "throwe"-t-on) ?
Par adresse, référence ou par copie ?
Pour autant que je sache, on ne peux pas lancer par référence.
Un bonne règle est de lancer par valeur et de catcher par référence
pour éviter le slicing.
La copie est plus naturelle, mais elle implique effectivement de
copier tout ça (donc de mouliner intérieurement du new et du
delete).
Je ne comprends pas ce que tu veux dire ici.
Reste à voir ce qu'on en fait à la fin (le catch).
Si le système d'exceptions est bien fait, d'une part on a une
hiérarchie bien claire permettant de cascader les catch
spécifiques et de se passer du catch-all (sauf pour faire un
cleanup intermédiaire suivi d'un rethrow).
Si je catche quelque chose, c'est que j'ai prévu de le traiter et
que personne ne pense pouvoir le faire dans une sosu-couche donc je
sais bien ce que je doit catcher.
Généralement on est bien embêté parce qu'on se tape pour
l'occasion une librairie plus ou moins exotique et on n'a pas trop
le temps de creuser son fonctionnement intime (c'est même ce qu'on
veut éviter - on a la pression bien sûr):
- Pour le détail des causes d'échec possibles, normalement, on
regarde les retours de la fonction appelée, et on fait un switch
avec un default... - Pour une exception, ça peut venir de plus
profond et donc c'est assez obtus. On ne veut pas en oublier une
parce que ça conduit à un plantage et c'est pas vendeur. Et ça
peut arriver par la suite avec une nouvelle version de ladite
librairie. D'où le choix du catch-all équivalent du défault...
Il y a plein de façon d'avoir une bibliothèque mal conçue en dehors
des exceptions.
[...]
D'expérience, souvent on voit un catch-all avec dedans un
printf("oh zut, ça a foiré") suivi de return(ERROR).
Il y a beaucoup de cas où il est difficile de trouver une façon
gracieuse de gérer l'erreur. S'assurer que l'utilisateur n'a pas
perdu de données et lui donner une idée du diagnostique est un
minimum mais souvent c'est déjà pas mal.
[...]
Moi j'aime pas trop les logiciels qui disent "au
secours, j'y arrive pas", de plus je fais dans le process
automatisé, alors souvent il n'y a personne pour lire le message.
Un petit mail à l'administrateur, ça fait toujours plaisir :)
Sinon Spirit dans Boost est base sur les memes concepts je crois mais
mes essais il y a 5-6 ans donnaient des temps de compilation
prohibitif pour des grammaires non trivial. Je suppose qu'aujourd'hui
le probleme est regle.
Sinon Spirit dans Boost est base sur les memes concepts je crois mais
mes essais il y a 5-6 ans donnaient des temps de compilation
prohibitif pour des grammaires non trivial. Je suppose qu'aujourd'hui
le probleme est regle.
Sinon Spirit dans Boost est base sur les memes concepts je crois mais
mes essais il y a 5-6 ans donnaient des temps de compilation
prohibitif pour des grammaires non trivial. Je suppose qu'aujourd'hui
le probleme est regle.
"Michael Doubez" a écrit dans le message
de news om
> On 5 juil, 11:41, "Patrick 'Zener' Brunet"
> wrote:
>> "Guillaume Gourdin" a écrit dans le message
>> de news 4a4f3042$0$30992$
>>> selon ma (modeste) expérience, les exceptions en C++sont très
>>> largement sous utilisées, et on en reste (me semble t-il) toujours
>>> à la bonne vieille méthode du retour d'un code d'erreur. Je suis
>>> un peu surpris de cet état de fait, les exceptions étant suppos ées
>>> apporter une gestion plus performantes des erreurs. J'ai dons
>>> quelques questions: est-il vrai que les exceptions sont sous
>>> utilisées? Quels sont vos retours d'expérience? Ou bien y a t'il
>>> une raison plus profonde à la sous-utilisation des exceptions?
>> En complément aux arguments de Fabien Le Lez, en lisant du code C++
>> utilisant des exceptions, on voit souvent des choses aussi lourdes
>> que risquées, qui peuvent donc "discréditer" les exceptions aux
>> yeux de certains.
>> Lancer une exception implique de la construire, donc il vaut mieux
>> que cette partie-là soit garantie.
> C'est pour ça qu'il y a la garantie nothrow. Mais dans le cas
> général, à moins d'un état grave de manque de mémoire, la
> construction des exceptions n'est pas un problème.
Effectivement, tirer une exceptions durant le traitement d'une autre, pou r
moi c'est du mauvais goût.
Mais avant ça, il y a l'échec de la construction de l'exception elle- même:
- par manque de mémoire si elle n'est pas pré-allouée,
- par échec d'une fonction de renseignement quelconque si on veut rempl ir un
diagnostic verbeux.
>> Il n'est pas rare de voir des exceptions créées par un new, et
>> pour faire bonne mesure, on insère tout un tas de diagnostics
>> dedans sous forme de strings...
> C'est du code à la Java.
Que nenni ! C'est si tentant en C++ de construire le message d'erreur eu
niveau du cas d'échec et de le faire transporter par l'exception.
Qui va donc contenir quelques strings et tout un fatras d'opérateurs << ou
concaténation (avec donc dans la string un maximum de réallocations d e
buffers).
>> Tout ça pour traiter un incident tels qu'un échec d'allocation de
>> mémoire ? Il doit bien y avoir des gens que ça ennuie...
> Je prefère une exception à un NULL à vérifier chaque fois.
On parle bien de la construction de l'exception elle-même, pas de l'obj et
qui va la provoquer.
Dans ce cas, moi aussi je préfère que l'op new génère une excepti on. Mais
s'il doit faire un malloc() pour ça, ça craint un peu.
> De toutes
> façons, je ne sais pas quoi faire si j'ai plus de mémoire, il y a
> peux de chance qu'essayer de nouveau marche. Le mieux est encore de
> revenir à un état antérieur qui se prétend capable de gérer l a
> situation.
Ben idéalement on peut envisager de libérer des choses pour restituer de la
mémoire. Anticiper un cleanup par exemple, retardé pour des raisons d e
performances...
Evidemment le scénario est discutable sur une station avec quelques Go de
RAM et un gros disque, mais sur un système embarqué un peu étroit e t pour
lequel on fait du process complexe qui nécessite de l'allocation dynami que
(un peu d'IA par exemple), c'est la bonne manière d'envisager les chose s.
A priori c'est-là la cause essentielle du divorce entre l'informatique
industrielle et celles "de gestion" et "avancée". Il serait temps de le s
réconcillier... Je ne vois rien de malsain dans une gestion de la mém oire en
temps que ressource comptabilisée plutôt que supposée "prévue suf fisante".
>> Ensuite, comment passe-t-on cette exception (que "throwe"-t-on) ?
>> Par adresse, référence ou par copie ?
> Pour autant que je sache, on ne peux pas lancer par référence.
> Un bonne règle est de lancer par valeur et de catcher par référen ce
> pour éviter le slicing.
Oui, j'ai été confus... On lance par valeur et on propage/manipule pa r
référence ensuite.
Ben en fait je ne sais pas vraiment comment ça s'implémente à la
compilation: à quel moment se fait le démontage de la pile par rappor t au
cycle de l'exception.
Parce qu'elle est instanciée en sommet de pile, et le catch se trouve b ien
plus profond... Si dans le bloc catch je déclare une variable automatiq ue,
elle se met où sur la pile ?
Est-ce que tous les compilos respectent une norme pour ça ?
Ce qui m'ennuie, c'est que si pour une raison quelconque le passage par
référence n'est que symbolique et qu'en fait techniquement il y a pas sage
par valeur, alors c'est pas grave si l'exception fait quelques octets, ma is
dans le cas d'un gros truc comme évoqué au début, a priori c'est mo nstrueux.
>> Si le système d'exceptions est bien fait, d'une part on a une
>> hiérarchie bien claire permettant de cascader les catch
>> spécifiques et de se passer du catch-all (sauf pour faire un
>> cleanup intermédiaire suivi d'un rethrow).
> Si je catche quelque chose, c'est que j'ai prévu de le traiter et
> que personne ne pense pouvoir le faire dans une sosu-couche donc je
> sais bien ce que je doit catcher.
Ben si on écrit un code utilisant la fonction DoMachin() de la librairi e
Toto v5.1, qui elle-même utilise la Tata v3.6 etc., on lit à fond la doc de
DoMachin(), et on fait confiance aux auteurs de Toto pour bien maîtrise r ce
qui sort de Tata...
Le problème, c'est de savoir s'ils ont bien anticipé la Tata v4.0, et aussi
ce qu'ils vont changer eux-mêmes dans Toto 6.0.
Avec les DLL, ça peut changer par en-dessous sans que le code appelant doive
forcément être recompilé, ensuite on est supposé être à l'aff ut des news et
lire tous les changelogs...
C'est stressant. On peut avoir envie de mettre un catch-all, au cas où.
On disait plus bas:
>> Généralement on est bien embêté parce qu'on se tape pour
>> l'occasion une librairie plus ou moins exotique et on n'a pas trop
>> le temps de creuser son fonctionnement intime (c'est même ce qu'on
>> veut éviter - on a la pression bien sûr):
>> - Pour le détail des causes d'échec possibles, normalement, on
>> regarde les retours de la fonction appelée, et on fait un switch
>> avec un default... - Pour une exception, ça peut venir de plus
>> profond et donc c'est assez obtus. On ne veut pas en oublier une
>> parce que ça conduit à un plantage et c'est pas vendeur. Et ça
>> peut arriver par la suite avec une nouvelle version de ladite
>> librairie. D'où le choix du catch-all équivalent du défault...
> Il y a plein de façon d'avoir une bibliothèque mal conçue en deho rs
> des exceptions.
Ah que oui ! Mais on a pas trop le choix, il faut vivre avec.
D'où la programmation défensive...
>> Moi j'aime pas trop les logiciels qui disent "au
>> secours, j'y arrive pas", de plus je fais dans le process
>> automatisé, alors souvent il n'y a personne pour lire le message.
> Un petit mail à l'administrateur, ça fait toujours plaisir :)
Ce genre de truc n'a pas d'email en général.
Exemple vécu (même pas besoin d'un missile, un trieur industriel):
La machine (1 hectare environ) est pilotée directement par des racks OS /9 ou
similaires, mais pour le contrôle de process on met volontiers du PC
(plusieurs rendondants éventuellement) parce que:
- c'est puissant pour pas cher,
- ça permet de faire des IHM évoluées que le client réclame,
- ça peut intégrer une DB Oracle ou Sybase,
- c'est moins impossible à interfacer avec du gros système COBOL (c ôté
compta),
- les développeurs qui connaissent se trouvent plus facilement sur le
marché,
- divers...
En fonctionnement normal, s'il y a un écran, il est dans une armoire et
personne ne le regarde, hors maintenance.
Quand bien même quelqu'un verrait la MessageBox "Erreur d'accès au fi chier
TOTO.DAT", la plupart des opérateurs ne savent même pas ce qu'est un
fichier.
Et si le responsable de prod intervient, il va bien comprendre "qu'il y a
une .erde avec l'informatique", mais ensuite ?
Usine bloquée à 2h00 du mat, 500 opérateurs qui poireautent, les ca mionneurs
aussi, le réassort de toute la distribution de la région pour le lend emain
première heure qui est compromis...
Là le responsable réveille son PDG qui réveille celui de la SSII, e t vous
imaginez la suite...
Donc à moins d'un tremblement de terre majeur, le process DOIT se
débrouiller tout seul :o)
Evidemment c'est très dûr à réussir, mais c'est quand même bien de ne pas y
renoncer d'emblée pour se faciliter le codage.
Alors on essaie de blinder au maximum et de récupérer à tout prix t out
problème qui peut l'être d'une manière quelconque.
"Michael Doubez" <michael.dou...@free.fr> a écrit dans le message
de news bb84beee-b957-40e7-8781-18dab5d03...@h8g2000yqm.googlegroups.c om
> On 5 juil, 11:41, "Patrick 'Zener' Brunet"
> <use.link.in.signat...@ddress.invalid> wrote:
>> "Guillaume Gourdin" <tr...@hotmail.com> a écrit dans le message
>> de news 4a4f3042$0$30992$426a7...@news.free.fr
>>> selon ma (modeste) expérience, les exceptions en C++sont très
>>> largement sous utilisées, et on en reste (me semble t-il) toujours
>>> à la bonne vieille méthode du retour d'un code d'erreur. Je suis
>>> un peu surpris de cet état de fait, les exceptions étant suppos ées
>>> apporter une gestion plus performantes des erreurs. J'ai dons
>>> quelques questions: est-il vrai que les exceptions sont sous
>>> utilisées? Quels sont vos retours d'expérience? Ou bien y a t'il
>>> une raison plus profonde à la sous-utilisation des exceptions?
>> En complément aux arguments de Fabien Le Lez, en lisant du code C++
>> utilisant des exceptions, on voit souvent des choses aussi lourdes
>> que risquées, qui peuvent donc "discréditer" les exceptions aux
>> yeux de certains.
>> Lancer une exception implique de la construire, donc il vaut mieux
>> que cette partie-là soit garantie.
> C'est pour ça qu'il y a la garantie nothrow. Mais dans le cas
> général, à moins d'un état grave de manque de mémoire, la
> construction des exceptions n'est pas un problème.
Effectivement, tirer une exceptions durant le traitement d'une autre, pou r
moi c'est du mauvais goût.
Mais avant ça, il y a l'échec de la construction de l'exception elle- même:
- par manque de mémoire si elle n'est pas pré-allouée,
- par échec d'une fonction de renseignement quelconque si on veut rempl ir un
diagnostic verbeux.
>> Il n'est pas rare de voir des exceptions créées par un new, et
>> pour faire bonne mesure, on insère tout un tas de diagnostics
>> dedans sous forme de strings...
> C'est du code à la Java.
Que nenni ! C'est si tentant en C++ de construire le message d'erreur eu
niveau du cas d'échec et de le faire transporter par l'exception.
Qui va donc contenir quelques strings et tout un fatras d'opérateurs << ou
concaténation (avec donc dans la string un maximum de réallocations d e
buffers).
>> Tout ça pour traiter un incident tels qu'un échec d'allocation de
>> mémoire ? Il doit bien y avoir des gens que ça ennuie...
> Je prefère une exception à un NULL à vérifier chaque fois.
On parle bien de la construction de l'exception elle-même, pas de l'obj et
qui va la provoquer.
Dans ce cas, moi aussi je préfère que l'op new génère une excepti on. Mais
s'il doit faire un malloc() pour ça, ça craint un peu.
> De toutes
> façons, je ne sais pas quoi faire si j'ai plus de mémoire, il y a
> peux de chance qu'essayer de nouveau marche. Le mieux est encore de
> revenir à un état antérieur qui se prétend capable de gérer l a
> situation.
Ben idéalement on peut envisager de libérer des choses pour restituer de la
mémoire. Anticiper un cleanup par exemple, retardé pour des raisons d e
performances...
Evidemment le scénario est discutable sur une station avec quelques Go de
RAM et un gros disque, mais sur un système embarqué un peu étroit e t pour
lequel on fait du process complexe qui nécessite de l'allocation dynami que
(un peu d'IA par exemple), c'est la bonne manière d'envisager les chose s.
A priori c'est-là la cause essentielle du divorce entre l'informatique
industrielle et celles "de gestion" et "avancée". Il serait temps de le s
réconcillier... Je ne vois rien de malsain dans une gestion de la mém oire en
temps que ressource comptabilisée plutôt que supposée "prévue suf fisante".
>> Ensuite, comment passe-t-on cette exception (que "throwe"-t-on) ?
>> Par adresse, référence ou par copie ?
> Pour autant que je sache, on ne peux pas lancer par référence.
> Un bonne règle est de lancer par valeur et de catcher par référen ce
> pour éviter le slicing.
Oui, j'ai été confus... On lance par valeur et on propage/manipule pa r
référence ensuite.
Ben en fait je ne sais pas vraiment comment ça s'implémente à la
compilation: à quel moment se fait le démontage de la pile par rappor t au
cycle de l'exception.
Parce qu'elle est instanciée en sommet de pile, et le catch se trouve b ien
plus profond... Si dans le bloc catch je déclare une variable automatiq ue,
elle se met où sur la pile ?
Est-ce que tous les compilos respectent une norme pour ça ?
Ce qui m'ennuie, c'est que si pour une raison quelconque le passage par
référence n'est que symbolique et qu'en fait techniquement il y a pas sage
par valeur, alors c'est pas grave si l'exception fait quelques octets, ma is
dans le cas d'un gros truc comme évoqué au début, a priori c'est mo nstrueux.
>> Si le système d'exceptions est bien fait, d'une part on a une
>> hiérarchie bien claire permettant de cascader les catch
>> spécifiques et de se passer du catch-all (sauf pour faire un
>> cleanup intermédiaire suivi d'un rethrow).
> Si je catche quelque chose, c'est que j'ai prévu de le traiter et
> que personne ne pense pouvoir le faire dans une sosu-couche donc je
> sais bien ce que je doit catcher.
Ben si on écrit un code utilisant la fonction DoMachin() de la librairi e
Toto v5.1, qui elle-même utilise la Tata v3.6 etc., on lit à fond la doc de
DoMachin(), et on fait confiance aux auteurs de Toto pour bien maîtrise r ce
qui sort de Tata...
Le problème, c'est de savoir s'ils ont bien anticipé la Tata v4.0, et aussi
ce qu'ils vont changer eux-mêmes dans Toto 6.0.
Avec les DLL, ça peut changer par en-dessous sans que le code appelant doive
forcément être recompilé, ensuite on est supposé être à l'aff ut des news et
lire tous les changelogs...
C'est stressant. On peut avoir envie de mettre un catch-all, au cas où.
On disait plus bas:
>> Généralement on est bien embêté parce qu'on se tape pour
>> l'occasion une librairie plus ou moins exotique et on n'a pas trop
>> le temps de creuser son fonctionnement intime (c'est même ce qu'on
>> veut éviter - on a la pression bien sûr):
>> - Pour le détail des causes d'échec possibles, normalement, on
>> regarde les retours de la fonction appelée, et on fait un switch
>> avec un default... - Pour une exception, ça peut venir de plus
>> profond et donc c'est assez obtus. On ne veut pas en oublier une
>> parce que ça conduit à un plantage et c'est pas vendeur. Et ça
>> peut arriver par la suite avec une nouvelle version de ladite
>> librairie. D'où le choix du catch-all équivalent du défault...
> Il y a plein de façon d'avoir une bibliothèque mal conçue en deho rs
> des exceptions.
Ah que oui ! Mais on a pas trop le choix, il faut vivre avec.
D'où la programmation défensive...
>> Moi j'aime pas trop les logiciels qui disent "au
>> secours, j'y arrive pas", de plus je fais dans le process
>> automatisé, alors souvent il n'y a personne pour lire le message.
> Un petit mail à l'administrateur, ça fait toujours plaisir :)
Ce genre de truc n'a pas d'email en général.
Exemple vécu (même pas besoin d'un missile, un trieur industriel):
La machine (1 hectare environ) est pilotée directement par des racks OS /9 ou
similaires, mais pour le contrôle de process on met volontiers du PC
(plusieurs rendondants éventuellement) parce que:
- c'est puissant pour pas cher,
- ça permet de faire des IHM évoluées que le client réclame,
- ça peut intégrer une DB Oracle ou Sybase,
- c'est moins impossible à interfacer avec du gros système COBOL (c ôté
compta),
- les développeurs qui connaissent se trouvent plus facilement sur le
marché,
- divers...
En fonctionnement normal, s'il y a un écran, il est dans une armoire et
personne ne le regarde, hors maintenance.
Quand bien même quelqu'un verrait la MessageBox "Erreur d'accès au fi chier
TOTO.DAT", la plupart des opérateurs ne savent même pas ce qu'est un
fichier.
Et si le responsable de prod intervient, il va bien comprendre "qu'il y a
une .erde avec l'informatique", mais ensuite ?
Usine bloquée à 2h00 du mat, 500 opérateurs qui poireautent, les ca mionneurs
aussi, le réassort de toute la distribution de la région pour le lend emain
première heure qui est compromis...
Là le responsable réveille son PDG qui réveille celui de la SSII, e t vous
imaginez la suite...
Donc à moins d'un tremblement de terre majeur, le process DOIT se
débrouiller tout seul :o)
Evidemment c'est très dûr à réussir, mais c'est quand même bien de ne pas y
renoncer d'emblée pour se faciliter le codage.
Alors on essaie de blinder au maximum et de récupérer à tout prix t out
problème qui peut l'être d'une manière quelconque.
"Michael Doubez" a écrit dans le message
de news om
> On 5 juil, 11:41, "Patrick 'Zener' Brunet"
> wrote:
>> "Guillaume Gourdin" a écrit dans le message
>> de news 4a4f3042$0$30992$
>>> selon ma (modeste) expérience, les exceptions en C++sont très
>>> largement sous utilisées, et on en reste (me semble t-il) toujours
>>> à la bonne vieille méthode du retour d'un code d'erreur. Je suis
>>> un peu surpris de cet état de fait, les exceptions étant suppos ées
>>> apporter une gestion plus performantes des erreurs. J'ai dons
>>> quelques questions: est-il vrai que les exceptions sont sous
>>> utilisées? Quels sont vos retours d'expérience? Ou bien y a t'il
>>> une raison plus profonde à la sous-utilisation des exceptions?
>> En complément aux arguments de Fabien Le Lez, en lisant du code C++
>> utilisant des exceptions, on voit souvent des choses aussi lourdes
>> que risquées, qui peuvent donc "discréditer" les exceptions aux
>> yeux de certains.
>> Lancer une exception implique de la construire, donc il vaut mieux
>> que cette partie-là soit garantie.
> C'est pour ça qu'il y a la garantie nothrow. Mais dans le cas
> général, à moins d'un état grave de manque de mémoire, la
> construction des exceptions n'est pas un problème.
Effectivement, tirer une exceptions durant le traitement d'une autre, pou r
moi c'est du mauvais goût.
Mais avant ça, il y a l'échec de la construction de l'exception elle- même:
- par manque de mémoire si elle n'est pas pré-allouée,
- par échec d'une fonction de renseignement quelconque si on veut rempl ir un
diagnostic verbeux.
>> Il n'est pas rare de voir des exceptions créées par un new, et
>> pour faire bonne mesure, on insère tout un tas de diagnostics
>> dedans sous forme de strings...
> C'est du code à la Java.
Que nenni ! C'est si tentant en C++ de construire le message d'erreur eu
niveau du cas d'échec et de le faire transporter par l'exception.
Qui va donc contenir quelques strings et tout un fatras d'opérateurs << ou
concaténation (avec donc dans la string un maximum de réallocations d e
buffers).
>> Tout ça pour traiter un incident tels qu'un échec d'allocation de
>> mémoire ? Il doit bien y avoir des gens que ça ennuie...
> Je prefère une exception à un NULL à vérifier chaque fois.
On parle bien de la construction de l'exception elle-même, pas de l'obj et
qui va la provoquer.
Dans ce cas, moi aussi je préfère que l'op new génère une excepti on. Mais
s'il doit faire un malloc() pour ça, ça craint un peu.
> De toutes
> façons, je ne sais pas quoi faire si j'ai plus de mémoire, il y a
> peux de chance qu'essayer de nouveau marche. Le mieux est encore de
> revenir à un état antérieur qui se prétend capable de gérer l a
> situation.
Ben idéalement on peut envisager de libérer des choses pour restituer de la
mémoire. Anticiper un cleanup par exemple, retardé pour des raisons d e
performances...
Evidemment le scénario est discutable sur une station avec quelques Go de
RAM et un gros disque, mais sur un système embarqué un peu étroit e t pour
lequel on fait du process complexe qui nécessite de l'allocation dynami que
(un peu d'IA par exemple), c'est la bonne manière d'envisager les chose s.
A priori c'est-là la cause essentielle du divorce entre l'informatique
industrielle et celles "de gestion" et "avancée". Il serait temps de le s
réconcillier... Je ne vois rien de malsain dans une gestion de la mém oire en
temps que ressource comptabilisée plutôt que supposée "prévue suf fisante".
>> Ensuite, comment passe-t-on cette exception (que "throwe"-t-on) ?
>> Par adresse, référence ou par copie ?
> Pour autant que je sache, on ne peux pas lancer par référence.
> Un bonne règle est de lancer par valeur et de catcher par référen ce
> pour éviter le slicing.
Oui, j'ai été confus... On lance par valeur et on propage/manipule pa r
référence ensuite.
Ben en fait je ne sais pas vraiment comment ça s'implémente à la
compilation: à quel moment se fait le démontage de la pile par rappor t au
cycle de l'exception.
Parce qu'elle est instanciée en sommet de pile, et le catch se trouve b ien
plus profond... Si dans le bloc catch je déclare une variable automatiq ue,
elle se met où sur la pile ?
Est-ce que tous les compilos respectent une norme pour ça ?
Ce qui m'ennuie, c'est que si pour une raison quelconque le passage par
référence n'est que symbolique et qu'en fait techniquement il y a pas sage
par valeur, alors c'est pas grave si l'exception fait quelques octets, ma is
dans le cas d'un gros truc comme évoqué au début, a priori c'est mo nstrueux.
>> Si le système d'exceptions est bien fait, d'une part on a une
>> hiérarchie bien claire permettant de cascader les catch
>> spécifiques et de se passer du catch-all (sauf pour faire un
>> cleanup intermédiaire suivi d'un rethrow).
> Si je catche quelque chose, c'est que j'ai prévu de le traiter et
> que personne ne pense pouvoir le faire dans une sosu-couche donc je
> sais bien ce que je doit catcher.
Ben si on écrit un code utilisant la fonction DoMachin() de la librairi e
Toto v5.1, qui elle-même utilise la Tata v3.6 etc., on lit à fond la doc de
DoMachin(), et on fait confiance aux auteurs de Toto pour bien maîtrise r ce
qui sort de Tata...
Le problème, c'est de savoir s'ils ont bien anticipé la Tata v4.0, et aussi
ce qu'ils vont changer eux-mêmes dans Toto 6.0.
Avec les DLL, ça peut changer par en-dessous sans que le code appelant doive
forcément être recompilé, ensuite on est supposé être à l'aff ut des news et
lire tous les changelogs...
C'est stressant. On peut avoir envie de mettre un catch-all, au cas où.
On disait plus bas:
>> Généralement on est bien embêté parce qu'on se tape pour
>> l'occasion une librairie plus ou moins exotique et on n'a pas trop
>> le temps de creuser son fonctionnement intime (c'est même ce qu'on
>> veut éviter - on a la pression bien sûr):
>> - Pour le détail des causes d'échec possibles, normalement, on
>> regarde les retours de la fonction appelée, et on fait un switch
>> avec un default... - Pour une exception, ça peut venir de plus
>> profond et donc c'est assez obtus. On ne veut pas en oublier une
>> parce que ça conduit à un plantage et c'est pas vendeur. Et ça
>> peut arriver par la suite avec une nouvelle version de ladite
>> librairie. D'où le choix du catch-all équivalent du défault...
> Il y a plein de façon d'avoir une bibliothèque mal conçue en deho rs
> des exceptions.
Ah que oui ! Mais on a pas trop le choix, il faut vivre avec.
D'où la programmation défensive...
>> Moi j'aime pas trop les logiciels qui disent "au
>> secours, j'y arrive pas", de plus je fais dans le process
>> automatisé, alors souvent il n'y a personne pour lire le message.
> Un petit mail à l'administrateur, ça fait toujours plaisir :)
Ce genre de truc n'a pas d'email en général.
Exemple vécu (même pas besoin d'un missile, un trieur industriel):
La machine (1 hectare environ) est pilotée directement par des racks OS /9 ou
similaires, mais pour le contrôle de process on met volontiers du PC
(plusieurs rendondants éventuellement) parce que:
- c'est puissant pour pas cher,
- ça permet de faire des IHM évoluées que le client réclame,
- ça peut intégrer une DB Oracle ou Sybase,
- c'est moins impossible à interfacer avec du gros système COBOL (c ôté
compta),
- les développeurs qui connaissent se trouvent plus facilement sur le
marché,
- divers...
En fonctionnement normal, s'il y a un écran, il est dans une armoire et
personne ne le regarde, hors maintenance.
Quand bien même quelqu'un verrait la MessageBox "Erreur d'accès au fi chier
TOTO.DAT", la plupart des opérateurs ne savent même pas ce qu'est un
fichier.
Et si le responsable de prod intervient, il va bien comprendre "qu'il y a
une .erde avec l'informatique", mais ensuite ?
Usine bloquée à 2h00 du mat, 500 opérateurs qui poireautent, les ca mionneurs
aussi, le réassort de toute la distribution de la région pour le lend emain
première heure qui est compromis...
Là le responsable réveille son PDG qui réveille celui de la SSII, e t vous
imaginez la suite...
Donc à moins d'un tremblement de terre majeur, le process DOIT se
débrouiller tout seul :o)
Evidemment c'est très dûr à réussir, mais c'est quand même bien de ne pas y
renoncer d'emblée pour se faciliter le codage.
Alors on essaie de blinder au maximum et de récupérer à tout prix t out
problème qui peut l'être d'une manière quelconque.
On 7 juil, 11:17, James Kanze wrote:
> Il n'a de signification pour le client qu'après l'échec
> d'une lecture (et c'est surtout une signification inversée
> -- s'il n'est pas positionné, alors que failbit l'est, c'est
> qu'il y a une erreur de format dans le fichier). La raison
> pourquoi il ne fait jamais de sens qu'il génère une
> exception, c'est précisement parce qu'il ne signifie rien
> pour le client, qu'il peut être positionné d'une façon un
> peu aléatoire, non selon ce qu'on vient de lire (ou qu'on
> vient d'essayer à lire), mais selon ce qui suit dans le
> fichier, et même la façon que istream fonctionne
> internellement.
? Pas tout compris... Si on voit un eofbit, c'est que la fin
de fichier a ete _effectivement_ vue, pas seulement que l'on
s'y trouve.
je pensais plutot a quelque chose comme:
if (! (readInt(parser) || readFloat(parser) || readDate(parser) ||
readString(parser)))
throw parser.error("syntax error: invalid field value");
note que c'est le parser lui-meme que je "throw", car il
contient les informations sur l'etat courant du parsing
(history, location, remaining, context) qui permet de
detailler le rapport de l'erreur.
On 7 juil, 11:17, James Kanze <james.ka...@gmail.com> wrote:
> Il n'a de signification pour le client qu'après l'échec
> d'une lecture (et c'est surtout une signification inversée
> -- s'il n'est pas positionné, alors que failbit l'est, c'est
> qu'il y a une erreur de format dans le fichier). La raison
> pourquoi il ne fait jamais de sens qu'il génère une
> exception, c'est précisement parce qu'il ne signifie rien
> pour le client, qu'il peut être positionné d'une façon un
> peu aléatoire, non selon ce qu'on vient de lire (ou qu'on
> vient d'essayer à lire), mais selon ce qui suit dans le
> fichier, et même la façon que istream fonctionne
> internellement.
? Pas tout compris... Si on voit un eofbit, c'est que la fin
de fichier a ete _effectivement_ vue, pas seulement que l'on
s'y trouve.
je pensais plutot a quelque chose comme:
if (! (readInt(parser) || readFloat(parser) || readDate(parser) ||
readString(parser)))
throw parser.error("syntax error: invalid field value");
note que c'est le parser lui-meme que je "throw", car il
contient les informations sur l'etat courant du parsing
(history, location, remaining, context) qui permet de
detailler le rapport de l'erreur.
On 7 juil, 11:17, James Kanze wrote:
> Il n'a de signification pour le client qu'après l'échec
> d'une lecture (et c'est surtout une signification inversée
> -- s'il n'est pas positionné, alors que failbit l'est, c'est
> qu'il y a une erreur de format dans le fichier). La raison
> pourquoi il ne fait jamais de sens qu'il génère une
> exception, c'est précisement parce qu'il ne signifie rien
> pour le client, qu'il peut être positionné d'une façon un
> peu aléatoire, non selon ce qu'on vient de lire (ou qu'on
> vient d'essayer à lire), mais selon ce qui suit dans le
> fichier, et même la façon que istream fonctionne
> internellement.
? Pas tout compris... Si on voit un eofbit, c'est que la fin
de fichier a ete _effectivement_ vue, pas seulement que l'on
s'y trouve.
je pensais plutot a quelque chose comme:
if (! (readInt(parser) || readFloat(parser) || readDate(parser) ||
readString(parser)))
throw parser.error("syntax error: invalid field value");
note que c'est le parser lui-meme que je "throw", car il
contient les informations sur l'etat courant du parsing
(history, location, remaining, context) qui permet de
detailler le rapport de l'erreur.
James Kanze a écrit :
>> Et si on veut traiter l'exception au plus proche de sa
>> survenue, on ne mettra pas "qui sait quoi de plus..." dans
>> le "try" !
> Ce qui impose que someAction() soit dans un bloc à soi, avec son
> propre portée. Quelque chose comme :
> try {
> MyType var = someAction() ;
> } catch ...
> ne va pas si var doit servir ulterieurement.
je déclare var au niveau de la fonction bien que ça contredise
la règle "déclarer les variables au plus proche de leur
utilisation". Je ne suis pas pour déclarer des variables dans
les blocs try.
James Kanze a écrit :
>> Et si on veut traiter l'exception au plus proche de sa
>> survenue, on ne mettra pas "qui sait quoi de plus..." dans
>> le "try" !
> Ce qui impose que someAction() soit dans un bloc à soi, avec son
> propre portée. Quelque chose comme :
> try {
> MyType var = someAction() ;
> } catch ...
> ne va pas si var doit servir ulterieurement.
je déclare var au niveau de la fonction bien que ça contredise
la règle "déclarer les variables au plus proche de leur
utilisation". Je ne suis pas pour déclarer des variables dans
les blocs try.
James Kanze a écrit :
>> Et si on veut traiter l'exception au plus proche de sa
>> survenue, on ne mettra pas "qui sait quoi de plus..." dans
>> le "try" !
> Ce qui impose que someAction() soit dans un bloc à soi, avec son
> propre portée. Quelque chose comme :
> try {
> MyType var = someAction() ;
> } catch ...
> ne va pas si var doit servir ulterieurement.
je déclare var au niveau de la fonction bien que ça contredise
la règle "déclarer les variables au plus proche de leur
utilisation". Je ne suis pas pour déclarer des variables dans
les blocs try.
James Kanze a écrit :
> La première publication sur la *possibilité* d'exceptions en C++
> date de 1989 ("Exception Handling for C++", de Koenig et
> Stroustrup).
suivi d'autres articles vers 1922-1994 avec des implémentations
concrètes de support d'exception (par setjmp/longjmp).
> Dans la pratique, dans l'industrie, on n'a pu réelement
> commencer à se servir des exceptions que vers 2000.
à s'en servir de manière standard (mots clés try, catch).
je les utilisais (et ce n'était pas un usage isolé) dès
1995-1996 dans tous mes codes C++ (CFront sous MPW/MacOS).
James Kanze a écrit :
> La première publication sur la *possibilité* d'exceptions en C++
> date de 1989 ("Exception Handling for C++", de Koenig et
> Stroustrup).
suivi d'autres articles vers 1922-1994 avec des implémentations
concrètes de support d'exception (par setjmp/longjmp).
> Dans la pratique, dans l'industrie, on n'a pu réelement
> commencer à se servir des exceptions que vers 2000.
à s'en servir de manière standard (mots clés try, catch).
je les utilisais (et ce n'était pas un usage isolé) dès
1995-1996 dans tous mes codes C++ (CFront sous MPW/MacOS).
James Kanze a écrit :
> La première publication sur la *possibilité* d'exceptions en C++
> date de 1989 ("Exception Handling for C++", de Koenig et
> Stroustrup).
suivi d'autres articles vers 1922-1994 avec des implémentations
concrètes de support d'exception (par setjmp/longjmp).
> Dans la pratique, dans l'industrie, on n'a pu réelement
> commencer à se servir des exceptions que vers 2000.
à s'en servir de manière standard (mots clés try, catch).
je les utilisais (et ce n'était pas un usage isolé) dès
1995-1996 dans tous mes codes C++ (CFront sous MPW/MacOS).
On Jul 7, 3:40 pm, Wykaaa wrote:James Kanze a écrit :
[...]Et si on veut traiter l'exception au plus proche de sa
survenue, on ne mettra pas "qui sait quoi de plus..." dans
le "try" !Ce qui impose que someAction() soit dans un bloc à soi, avec son
propre portée. Quelque chose comme :try {
MyType var = someAction() ;
} catch ...ne va pas si var doit servir ulterieurement.je déclare var au niveau de la fonction bien que ça contredise
la règle "déclarer les variables au plus proche de leur
utilisation". Je ne suis pas pour déclarer des variables dans
les blocs try.
D'abord, tu ne peux pas forcément. Si par exemple le type de la
variable n'a pas de constructeur par défaut, ou ne support pas
l'affectation. Mais aussi, en ce faisant, tu passes à côté d'une
des points forts des exceptions dans les constructeurs ; si le
constructeur n'a pas pû correctement construire l'objet, tu n'as
pas d'objet accessible. C'est un avantage assez important pour
justifier le désavantage de l'éloignement du traitement
d'erreur. (Dans ce cas-là, je mets en général tout le
traitement dans une fonction à part, pour pouvoir écrire :
try {
MyType object( initialisateurs ) ;
object.toutLeTraitement() ;
} catch ...
Ce qui limite l'éloignement.)
On Jul 7, 3:40 pm, Wykaaa <wyk...@yahoo.fr> wrote:
James Kanze a écrit :
[...]
Et si on veut traiter l'exception au plus proche de sa
survenue, on ne mettra pas "qui sait quoi de plus..." dans
le "try" !
Ce qui impose que someAction() soit dans un bloc à soi, avec son
propre portée. Quelque chose comme :
try {
MyType var = someAction() ;
} catch ...
ne va pas si var doit servir ulterieurement.
je déclare var au niveau de la fonction bien que ça contredise
la règle "déclarer les variables au plus proche de leur
utilisation". Je ne suis pas pour déclarer des variables dans
les blocs try.
D'abord, tu ne peux pas forcément. Si par exemple le type de la
variable n'a pas de constructeur par défaut, ou ne support pas
l'affectation. Mais aussi, en ce faisant, tu passes à côté d'une
des points forts des exceptions dans les constructeurs ; si le
constructeur n'a pas pû correctement construire l'objet, tu n'as
pas d'objet accessible. C'est un avantage assez important pour
justifier le désavantage de l'éloignement du traitement
d'erreur. (Dans ce cas-là, je mets en général tout le
traitement dans une fonction à part, pour pouvoir écrire :
try {
MyType object( initialisateurs ) ;
object.toutLeTraitement() ;
} catch ...
Ce qui limite l'éloignement.)
On Jul 7, 3:40 pm, Wykaaa wrote:James Kanze a écrit :
[...]Et si on veut traiter l'exception au plus proche de sa
survenue, on ne mettra pas "qui sait quoi de plus..." dans
le "try" !Ce qui impose que someAction() soit dans un bloc à soi, avec son
propre portée. Quelque chose comme :try {
MyType var = someAction() ;
} catch ...ne va pas si var doit servir ulterieurement.je déclare var au niveau de la fonction bien que ça contredise
la règle "déclarer les variables au plus proche de leur
utilisation". Je ne suis pas pour déclarer des variables dans
les blocs try.
D'abord, tu ne peux pas forcément. Si par exemple le type de la
variable n'a pas de constructeur par défaut, ou ne support pas
l'affectation. Mais aussi, en ce faisant, tu passes à côté d'une
des points forts des exceptions dans les constructeurs ; si le
constructeur n'a pas pû correctement construire l'objet, tu n'as
pas d'objet accessible. C'est un avantage assez important pour
justifier le désavantage de l'éloignement du traitement
d'erreur. (Dans ce cas-là, je mets en général tout le
traitement dans une fonction à part, pour pouvoir écrire :
try {
MyType object( initialisateurs ) ;
object.toutLeTraitement() ;
} catch ...
Ce qui limite l'éloignement.)
On Jul 7, 2:50 pm, ld wrote:
> On 7 juil, 11:17, James Kanze wrote:
> > Il n'a de signification pour le client qu'après l'échec
> > d'une lecture (et c'est surtout une signification inversée
> > -- s'il n'est pas positionné, alors que failbit l'est, c'est
> > qu'il y a une erreur de format dans le fichier). La raison
> > pourquoi il ne fait jamais de sens qu'il génère une
> > exception, c'est précisement parce qu'il ne signifie rien
> > pour le client, qu'il peut être positionné d'une façon un
> > peu aléatoire, non selon ce qu'on vient de lire (ou qu'on
> > vient d'essayer à lire), mais selon ce qui suit dans le
> > fichier, et même la façon que istream fonctionne
> > internellement.
> ? Pas tout compris... Si on voit un eofbit, c'est que la fin
> de fichier a ete _effectivement_ vue, pas seulement que l'on
> s'y trouve.
Pas au niveau du client. Essaie :
int
main()
{
std::istringstream s( "1.23" ) ; // pas de 'n' final !!!
double d ;
s >> d ;
std::cout << s.eof() << std::endl ;
return 0 ;
}
Après le « s >> d », le client n'a pas encore rencontré la fi n ;
il a bien lu son double. Mais normalement, le eofbit sera
positionné.
Indépendamment de l'utilisation de l'exception, oui, il faut
bien incorporer des informations du parser dans le rapport de
l'erreur. D'habitude, je fais quelque chose du genre :
parser.error( severity ) << "invalid field value: " << value ;
(Voire simplement « error( severity )... », si je suis dans une
fonction du parseur, ce qui est généralement le cas.) Ensuite,
le destructeur du temporaire renvoyé par la fonction error fait
ce qu'il faut -- si on veut une exception, c'est là (eh oui,
dans le destructeur) qu'on la lève.
On Jul 7, 2:50 pm, ld <Laurent.Den...@gmail.com> wrote:
> On 7 juil, 11:17, James Kanze <james.ka...@gmail.com> wrote:
> > Il n'a de signification pour le client qu'après l'échec
> > d'une lecture (et c'est surtout une signification inversée
> > -- s'il n'est pas positionné, alors que failbit l'est, c'est
> > qu'il y a une erreur de format dans le fichier). La raison
> > pourquoi il ne fait jamais de sens qu'il génère une
> > exception, c'est précisement parce qu'il ne signifie rien
> > pour le client, qu'il peut être positionné d'une façon un
> > peu aléatoire, non selon ce qu'on vient de lire (ou qu'on
> > vient d'essayer à lire), mais selon ce qui suit dans le
> > fichier, et même la façon que istream fonctionne
> > internellement.
> ? Pas tout compris... Si on voit un eofbit, c'est que la fin
> de fichier a ete _effectivement_ vue, pas seulement que l'on
> s'y trouve.
Pas au niveau du client. Essaie :
int
main()
{
std::istringstream s( "1.23" ) ; // pas de 'n' final !!!
double d ;
s >> d ;
std::cout << s.eof() << std::endl ;
return 0 ;
}
Après le « s >> d », le client n'a pas encore rencontré la fi n ;
il a bien lu son double. Mais normalement, le eofbit sera
positionné.
Indépendamment de l'utilisation de l'exception, oui, il faut
bien incorporer des informations du parser dans le rapport de
l'erreur. D'habitude, je fais quelque chose du genre :
parser.error( severity ) << "invalid field value: " << value ;
(Voire simplement « error( severity )... », si je suis dans une
fonction du parseur, ce qui est généralement le cas.) Ensuite,
le destructeur du temporaire renvoyé par la fonction error fait
ce qu'il faut -- si on veut une exception, c'est là (eh oui,
dans le destructeur) qu'on la lève.
On Jul 7, 2:50 pm, ld wrote:
> On 7 juil, 11:17, James Kanze wrote:
> > Il n'a de signification pour le client qu'après l'échec
> > d'une lecture (et c'est surtout une signification inversée
> > -- s'il n'est pas positionné, alors que failbit l'est, c'est
> > qu'il y a une erreur de format dans le fichier). La raison
> > pourquoi il ne fait jamais de sens qu'il génère une
> > exception, c'est précisement parce qu'il ne signifie rien
> > pour le client, qu'il peut être positionné d'une façon un
> > peu aléatoire, non selon ce qu'on vient de lire (ou qu'on
> > vient d'essayer à lire), mais selon ce qui suit dans le
> > fichier, et même la façon que istream fonctionne
> > internellement.
> ? Pas tout compris... Si on voit un eofbit, c'est que la fin
> de fichier a ete _effectivement_ vue, pas seulement que l'on
> s'y trouve.
Pas au niveau du client. Essaie :
int
main()
{
std::istringstream s( "1.23" ) ; // pas de 'n' final !!!
double d ;
s >> d ;
std::cout << s.eof() << std::endl ;
return 0 ;
}
Après le « s >> d », le client n'a pas encore rencontré la fi n ;
il a bien lu son double. Mais normalement, le eofbit sera
positionné.
Indépendamment de l'utilisation de l'exception, oui, il faut
bien incorporer des informations du parser dans le rapport de
l'erreur. D'habitude, je fais quelque chose du genre :
parser.error( severity ) << "invalid field value: " << value ;
(Voire simplement « error( severity )... », si je suis dans une
fonction du parseur, ce qui est généralement le cas.) Ensuite,
le destructeur du temporaire renvoyé par la fonction error fait
ce qu'il faut -- si on veut une exception, c'est là (eh oui,
dans le destructeur) qu'on la lève.