IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Retour de fonctions ou exceptions ? [Tutoriel]


Sujet :

C++

  1. #21
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    De manière générale, il y a des subtilités en matière de conception-développement...les pièges , fausses bonnes idées, etc...dont tu parles sont la raison pour laquelle il faut concevoir le modèle d'erreur comme on doit concevoir le reste de l'application: avec soin, en réfléchissant à ce qu'on fait, sauf à décider que l'application est légère et jetable...

  2. #22
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par bugsan Voir le message
    Par exemple un service qui se nomme "findQuelquechose", si il ne trouve rien, doit il retourner null, ou lancer une exception ?
    Pour moi c'est le comportement normal et que j'attends d'un findXX.
    L'action de find n'assure pas de trouver quelque chose, sinon ce serait un get.
    Cf une discussion que je ne retrouve plus, où l'auteur avait une fonction find qui parsait et trouvait ce qui correspondait dans une liste. Il assurait que ce qu'il cherchait était toujours dans la liste, mais avait un warning à la compilation : tous les chemins de la fonctions n'avaient pas de return. Il ne comprenait pas pourquoi alors que sa fonction ne pouvait pas ne rien trouver.
    La fonction est mal nommée, si on est sûr de trouver, find n'est pas approprié, get l'est déjà plus. Ensuite, protéger la fonction par un assert (ou une exception, mais l'assert sera préférable amha) dans le cas (impossible d'après lui et ce qu'il souhaitait mettre en place/utiliser) où effectivement rien n'était trouvé.


    Citation Envoyé par bugsan Voir le message
    Par exemple une méthode "persist" qui n'a pas réussi a persister la donnée, elle doit lancer une exception. Si on souhaite la coder en mode "code retour", on peut, mais dans ce cas je la nommerais "tryPersist", car on suggère que la méthode peut échouer sans grande gravité ...
    Oui un persist pourrait lever une exception, mais écarter le code retour en cas d'échec est totalement injustifié.
    Un code retour est tout à fait applicable et équivalent à l'exception.
    Et renommer la fonction en tryPersist n'est pas plus justifié et inutile. Sinon autant renommer toutes tes fonctions en tryFunction : après tout, toutes tes méthodes peuvent potentiellement échouer et/ou renvoyer une exception.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #23
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    AMHA, il y a quand même une différence entre code de retour et exceptions.

    Un code de retour est une gestion d'erreurs opt-in, une exception est opt-out.

    En gros : Un mauvais dév qui arrive sur le code va se planter avec les codes de retour, et pourra faire tout péter, simplement parce qu'il n'aura pas pensé à vérifier un code de retour.
    Un mauvais dév avec des exceptions, ça limite les dégâts : pour annuler l'exception, il faut le faire consciemment.

    Voilà mon petit grain de sel !

  4. #24
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Oui un persist pourrait lever une exception, mais écarter le code retour en cas d'échec est totalement injustifié.
    Un code retour est tout à fait applicable et équivalent à l'exception.
    C'est là qu'on diverge: je trouve le code de retour nettement plus risqué car on peut négliger de le traiter et se demander ensuite d'où vient l'absence des données...
    S'il existe mettons un cas d'utilisation où l'échec de la persistance peut être compensé, on met en place cette compensation dans un handler d'exception

  5. #25
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    AMHA, il y a quand même une différence entre code de retour et exceptions.

    Un code de retour est une gestion d'erreurs opt-in, une exception est opt-out.

    En gros : Un mauvais dév qui arrive sur le code va se planter avec les codes de retour, et pourra faire tout péter, simplement parce qu'il n'aura pas pensé à vérifier un code de retour.
    Un mauvais dév avec des exceptions, ça limite les dégâts : pour annuler l'exception, il faut le faire consciemment.

    Voilà mon petit grain de sel !
    ++
    je pense comme toi que ça sécurise bien plus les développements sur le long terme (et sur de gros projets le long terme...arrive vite)

  6. #26
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    En gros : Un mauvais dév qui arrive sur le code va se planter avec les codes de retour, et pourra faire tout péter, simplement parce qu'il n'aura pas pensé à vérifier un code de retour.
    Cela n'est-t-il pas évitable avec un compilateur qui te signale qu'une valeur de retour n'est pas récupérée ?

  7. #27
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    On en arrive avec du compiler-specific : __attribute__((warn_unused_result)).

    Et, même là, on a toujours une faille : le pauvre dév' pas doué qui ne comprend pas le message d'erreur va regarder sur internet.

    Un exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <iostream>
     
    int foo() __attribute__ ((warn_unused_result));
     
    int foo() {
       return 42;
    }
     
    int main() {
       foo();
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ g++ a.cpp 
    a.cpp: In function 'int main()':
    a.cpp:10:9: warning: ignoring return value of 'int foo()', declared with attribute warn_unused_result [-Wunused-result]
    => Google "g++ warning: ignoring return value of declared with attribute warn_unused_result [-Wunused-result]"

    Premier résultat : http://www.unix.com/unix-dummies-que...g-program.html

    => "Most of those are warnings and probably safe to ignore"

    => Et voilà, le warning est ignoré.

    Mais bon, il faut avouer que warn_unused_result réduit les soucis.
    Enfin, seulement quand on utilise g++, hein. Parce qu'après pour le rendre fonctionnel sur tous les compilateurs, bon courage !

  8. #28
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Je dirais même que les warnings sont très souvent ignorés par les devs soit parce qu'ils ont encore à progresser soit parce que l'environnement n'est pas favorable (pression des délais, etc...)
    Donc en utilisant une exception, on assure le comportement de traitement d'erreur de base (interrompre le traitement avant que la corruption de l'état du programme ne dégénère), et à partir de là on peut faire ce qui s'impose:
    • corriger le code appelant, car le plantage dû à son défaut ne peut plus être ignoré par négligence ou inconscience quand il met fin au traitement
    • appliquer une logique de compensation si on peut en concevoir une
    • parfois même ne rien faire de plus car l'arrêt du traitement dû à l'exception (avec un message idoine) peut parfois être une réaction suffisante en première analyse (ex: données corrompues en entrée non testées par le côté appelant)

  9. #29
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Très bonne analyse therwald, et j'utilise pour ma part parfois des assert justement pour forcer certains dev à ne pas faire n'importe quoi car ils sont capable de simplement attraper une exception juste pour qu'on ne la voie plus, sans parler des codes de retours qui ne sont pseudo-traités que pour que la validation statique passe dans 95% des cas (si ce n'est plus). C'est triste d'en arriver à là
    Find me on github

  10. #30
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Le gros problème des retours d'erreur, même si on les récupère dans la fonction appelante, c'est qu'il y a :

    Les code d'erreur renvoyés directement par la fonction, dont on peut *espérer* avoir un aperçu suffisant pour connaitre l'ensemble des code, mais peut aussi (il ne faut pas se leurrer ) renvoyer des codes d'erreur renvoyés par les fonctions qu'elle appelle ell-même, et là, il devient beaucoup plus difficile d'avoir la certitude que tous les codes d'erreur sont pris en compte.

    Même si le retour d'erreur prend la forme d'une énumération, il est tout à fait possible de (allez, j'ose utiliser le terme ) "contourner" le compilateur et d'éviter l'avertissement qu'il émet en utilisant simplement un switch + quelques case + default.

    Mais si on passe dans default, peut on avoir la certitude que la gestion des erreurs sera ne serait-ce qu'à peu près correcte
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #31
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    ++
    Une clause default pourra très facilement consister à "avaler" l'erreur, perdant l'information sur le code d'origine. Alors que le "chemin de moindre résistance" en ce qui concerne les exceptions est de laisser faire le mécanisme par défaut...
    Vérifier dans une fonction que son domaine de définition est respecté a de plus pour moi l'avantage de centraliser ce contrôle, donc de faire écrire le code par celui qui sait le mieux définir ces conditions. Et l'émission d'une exception en réponse à ce problème a pour moi les avantages que j'ai énumérés dans mon dernier post. De plus, s'agissant de valeurs d'entrée foireuses, on reste dans le cadre d'une situation exceptionnelle, puisque les valeurs d'entrée sont censées être correctes...

  12. #32
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Mais si le développeur absorbe l'erreur par un switch... à qui la faute ?!
    Ce n'est pas du tout une raison pour préférer une exception à une erreur, au lieu d'un switch/default il mettra un try {} catch {} et même combat.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #33
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Il ne s'agit pas de savoir "à qui la faute". Par ailleurs, comme rien ne l'oblige à catcher, la pente naturelle conduira à ne rien faire. Donc l'exception interrompra le traitement, ce qui dans pas mal de cas (je ne vais pas me répéter) est le mieux à faire. Et en plus des effets persistants, mieux vaut débugger une erreur détectée au plus tôt possible que tenter de comprendre un état corrompu à mort par une série de glissage de poussière sous le tapis.

  14. #34
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Citation Envoyé par Hylvenir Voir le message
    a-
    Par contre, pour avoir un core, j'active le core, et en cas de plantage, je sais où je suis, et mon état. pas besoin d'assert pour ça.

    b- Dans mon projet actuel, on peut revenir facilement à un état stable et le client ne veut surtout pas avoir de trou dans le service. On préfère donc des logs clairs afin de voir ce qui c'est passé plutôt qu'une interruption de service.
    a- Allons allons.
    Combien de cores sont bien au point où le véritable problème aurait pu être détecté ? C et C++ aiment bien continuer avec des aberrations tant qu'elles ne tentent rien d'explosif.
    L'assertion nous permet de stopper à des points plus intéressants pour nous.

    b- Quand je parle d'assertions, je ne parle jamais du mode "en opération" d'un code déployé chez le client. Mais toujours des modes : le code tourne chez nous: du test bidon à certains tests de validation [i.e. il faut aussi faire des tests en opérationnel pour vérifier les comportements en cas de plantage de sous-composants p.ex., ou pour voir les réactions à d'éventuelles erreurs de programmation] en passant par les TUs.

    Citation Envoyé par koala01 Voir le message
    Or, les exceptions permettent justement les deux comportements intéressants, ce qui n'est pas forcément le cas des retours d'erreurs, car, si on ne teste pas l'ensemble des codes d'erreur, elle peut très facilement "passer inaperçue"
    Je suis en total accord avec ton post jusque ici.
    Mais une exception ne permet pas d'avoir un snapshot de l'état du programme au moment du plantage.
    Si elle est très bien pour le mode opératoire et que l'on n'a pas une totale confiance en certains chemins du programme (auta-t-on toujours testé les pré-condition dans le code client avant de faire appel à un algo qui suppose que tout est dans le domaine de définition ?), ce n'est pas le cas pour le mode de réalisation car elle perd le contexte (à moins qu'il n'y ait pas un seul catch adapté dans le programme).
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  15. #35
    Membre confirmé
    Inscrit en
    Octobre 2007
    Messages
    210
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 210
    Points : 459
    Points
    459
    Par défaut
    En ce qui me concerne, je fais remonter tous les échecs en exception. Et je ne me soucis de catcher les exceptions uniquement lorsqu'il y a des ressources à fermer. Si ce sont des unchecked exception j'utilise simplement la clause finally.

    Si je procède comme cela, c'est parce que dans 99% des cas, je ne sais pas quoi faire de + en cas d'échec. Le mieux que je puisse faire, c'est wrapper l'exception dans le but de lui ajouter des informations contextuelles, ou pour éviter que les couches supérieures aient à dépendre d'exception bas niveau.

    Je laisse tout remonter jusqu'à l'IHM, et là je m'applique à mapper les différents messages d'erreur.


    Je ne vois pas comment faire la même chose avec des codes d'erreur, si il fallait les faire remonter jusqu'à l'interface. Il faudrait les gérer dans chaque appel de fonction... c'est selon moi un gros bordel :s

  16. #36
    Membre actif
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 176
    Points : 258
    Points
    258
    Par défaut
    Citation Envoyé par bugsan Voir le message
    ... Si ce sont des unchecked exception j'utilise simplement la clause finally.
    en C++ ?

  17. #37
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Il me semble qu'en utilisant RAII la libération est automatique en cas d'exception puisqu'on sort du scope...

  18. #38
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 168
    Points : 140
    Points
    140
    Par défaut
    Citation Envoyé par GeantVert13 Voir le message
    en C++ ?
    Si tu as un catch qui attrape l'exception et dans lequel tu ne fais aucun throw, tout ce qui se trouve après le/les catch(s) est exécuté.
    C'est une sorte de finally.

    Par contre, il faut que l'exception soit catché dans la fonction qui a produit l'exception.

  19. #39
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Citation Envoyé par Drannor Voir le message
    Si tu as un catch qui attrape l'exception et dans lequel tu ne fais aucun throw, tout ce qui se trouve après le/les catch(s) est exécuté.
    C'est une sorte de finally.

    Par contre, il faut que l'exception soit catché dans la fonction qui fait le throw.
    D'où l'intérêt d'utiliser finally si tu veux être sûr de l'exécution de ton code à la sortie du bloc. EDIT: j'ma mélangé ... comme le dit Lhermitte ci-dessous, utilises RAII, c'est ça qui est fiable.
    Du coup:
    1) tu es sûr que le code s'exécute même si l'exception n'est pas catchée
    2) tu évites le catch all qui ne fait rien, et qui est sauf cas particulier le plus mauvais choix. Encore une fois, si tu ne sais pas ce qu'est l'exception, alors tu ne sais pas quoi en faire donc tu dois la laisser filer, point barre. Le seul cas que je vois serait le cas où ton code est le superviseur d'une série de tâches complètement indépendantes et où en plus tu dois assurer l'exécution des autres tâches quand l'une d'entre elles plante. (le genre serveur d'applications)

  20. #40
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Citation Envoyé par Drannor Voir le message
    Si tu as un catch qui attrape l'exception et dans lequel tu ne fais aucun throw, tout ce qui se trouve après le/les catch(s) est exécuté.
    C'est une sorte de finally.

    Par contre, il faut que l'exception soit catché dans la fonction qui a produit l'exception.
    Tout l'intérêt du finally c'est d'assurer qu'un bout de code sera exécuté même si une exception est lancée. Pourquoi (vu qu'il n'y a pas de finally en C++) alors la rattraper pour la rebalancer (ce qui va exiger de dupliquer le code dont l'exécution doit être assurée).

    Non franchement.

    Mauvais outil. En C++, c'est le job du RAII.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. Retour de fonction en C
    Par troumad dans le forum Linux
    Réponses: 2
    Dernier message: 06/11/2005, 21h43
  2. Utilisation d'un retour de fonction dans un decode
    Par CFVince dans le forum Oracle
    Réponses: 4
    Dernier message: 20/10/2005, 17h22
  3. Référence en retour de fonction, à transformer en hash
    Par raoulchatigre dans le forum Langage
    Réponses: 4
    Dernier message: 15/07/2005, 14h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo