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

Création de jeux vidéo Discussion :

L'usage d'assert dans tests unitaires pour les jeux vidéos


Sujet :

Création de jeux vidéo

  1. #21
    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
    Oui enfin, si tu prends que la partie la plus absurde de ma réponse et omet la partie "intéressante" aussi..

    Tu veux un exemple concret ? Dans certains systèmes critiques et/ou embarqués, il est interdit de planter, et toutes les API sont basées sur des code retour.
    Si par hasard une exception arrive, l'appli crash direct et crée un core dump. Et c'est immédiatement remonté jusque nous pour comprendre l'origine et la fixer.

    En ce moment je travaille avec une API en C++/CLI, et c'est de loin le truc le plus dégueulasse que j'ai jamais vu, en particulier à cause de la gestion d'erreur faîte à coup d'exception, ça fait du try catch dans tous les sens (parce que comme dit plus haut, je suis dans un secteur où le constructeur interdit l'application à devenir instable - tant que faire ce peut), et c'est immonde à voir. En plus de tous ces "cross-os call" qui rendent le debug très chiant parce que tu ne sais pas ce que ta T^ possède pour ces membres.
    Sur une autre plateforme, l'API est en C, quelques bouts en C++, avec code erreur, et c'est enfantin à comprendre, très simple à mettre en place et tout autant à debuger.
    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.

  2. #22
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    393
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 393
    Points : 685
    Points
    685
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Oui enfin, si tu prends que la partie la plus absurde de ma réponse et omet la partie "intéressante" aussi..
    Tu veux dire le "Les codes erreurs, c'est justement pour être vérifié" ?
    Que veux tu que je dise sur ce point ? C'est une erreur très commune de ne pas gérer correctement les retours de fonction. Donc oui, elles devraient être vérifiées. Mais ce n'est pas le cas.

    Citation Envoyé par Bousk Voir le message
    Tu veux un exemple concret ? Dans certains systèmes critiques et/ou embarqués, il est interdit de planter, et toutes les API sont basées sur des code retour.
    Si par hasard une exception arrive, l'appli crash direct et crée un core dump. Et c'est immédiatement remonté jusque nous pour comprendre l'origine et la fixer.

    En ce moment je travaille avec une API en C++/CLI, et c'est de loin le truc le plus dégueulasse que j'ai jamais vu, en particulier à cause de la gestion d'erreur faîte à coup d'exception, ça fait du try catch dans tous les sens (parce que comme dit plus haut, je suis dans un secteur où le constructeur interdit l'application à devenir instable - tant que faire ce peut), et c'est immonde à voir. En plus de tous ces "cross-os call" qui rendent le debug très chiant parce que tu ne sais pas ce que ta T^ possède pour ces membres.
    Sur une autre plateforme, l'API est en C, quelques bouts en C++, avec code erreur, et c'est enfantin à comprendre, très simple à mettre en place et tout autant à debuger.
    Un code de retour peut être oublié (ou cas probablement plus courant, on ajoute un nouveau code d'erreur, il faut mettre a jour tous les codes appelant, mais on en oublie). Et ce type de problème peut mener a un UB, qui va crasher l'application, mais sans fournir de contexte de débogage correct. Cela va demander plus de temps a corriger.
    Dans la même situation, si on oublie de catcher une exception, on le sait tout de suite. Cela diminue les risques d'oublier de gérer correctement une erreur.

  3. #23
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par mintho carmo Voir le message
    (ou cas probablement plus courant, on ajoute un nouveau code d'erreur, il faut mettre a jour tous les codes appelant, mais on en oublie).
    Je ne comprend pas.

    Pour les cas d'erreurs, je pense qu'on a généralement 3 cas :
    • 0 = erreur, regarder errno pour plus d'informations ;
    • < 0 = erreur ;
    • ! 0 = erreur.


    Dans les trois cas, je vois mal comment on pourrait oublier une erreur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    if( ! result )
    {
         switch( errno )
         {
              default:
                   // erreur inconnue
              break;
         }
    }
     
    if( result )
    {
         switch( result )
         {
              default:
                   // erreur inconnue
              break;
         }
    }
     
     
     
    if( result < 0 )
    {
         switch( result )
         {
              default:
                   // erreur inconnue
              break;
         }
    }
    Dans tout les cas, ajouter un nouveau code d'erreur ne me coûte rien.

  4. #24
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    393
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 393
    Points : 685
    Points
    685
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Dans les trois cas, je vois mal comment on pourrait oublier une erreur.
    Cela te garantie de passer par ton code de gestion des erreurs, pas que ton erreur est correctement gérée. Et c'est bien le plus important dans la gestion des erreurs (faire en sorte que le programme reste dans un état valide).
    Si tu dois faire un traitement particulier après une erreur pour que le programme reste valide, tu ne lanceras dans ton switch que les erreurs que tu connais, au moment ou tu écris ton switch. Si tu ajoutes ensuite un nouveau code d'erreur, qui nécessite un nouveau traitement spécifique, ton switch n'est plus valide (ie il ne lance pas le traitement adéquate pour cette erreur spécifique).

    Dans le meilleur des cas, si tu as une nouvelle erreur et que le traitement "par défaut" est suffisant, tu n'auras pas de problème. Par exemple, si tu détectes une erreur sur la lecture d'un fichier et que par défaut, ta fonction "open" ne retourne aucune donnée en cas d'erreur, alors un nouveau type d'erreur ne posera pas de problème avec ton switch (il n'y aura aucun traitement spécifique pour cette nouvelle erreur, mais cela convient dans ce cas).
    Maintenant, si tu ajoutes une lecture de fichier asynchrone et que tu as une erreur en cours de lecture (donc après avoir envoyé une partie des données). La gestion de cette erreur nécessite de stopper les traitements sur les données déjà envoyer puis de les supprimer. Et la, ton switch capturera une erreur, mais ne fera pas le traitement adéquate. Ton programme est dans un état instable, ce qui est potentiellement plus grave qu'un crash.

    Avec une exception, tu as juste a creer un nouveau type d'exception "asynchrone_read_file_error" par exemple. Cette exception n’étant pas gérée dans le code actuel, si tu oublies de mettre a jour a un endroit de ton code ta gestion des erreurs pour prendre en compte cette erreur, tu auras un beau crash, avec un message d'erreur explicite "telle exception non catchee". C'est largement préférable a une erreur non gérée correctement (et surtout - pour en revenir au sujet de cette discussion - cela pourra être détectée par tes tests, plus facilement qu'une erreur non gérée)

  5. #25
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Mais dans ce cas là, qu'est-ce qui nous empêcherait de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    if( ! result )
    {
         switch( errno )
         {
              default:
                   std::cerr << "Erreur inconnue de code : " << errno << std::endl;
                   exit(1);
              break;
         }
    }
    Cela revient au même que ton exception non-catchée, non ?

  6. #26
    Membre éclairé

    Profil pro
    Inscrit en
    Décembre 2013
    Messages
    393
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 393
    Points : 685
    Points
    685
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Mais dans ce cas là, qu'est-ce qui nous empêcherait de faire :
    Rien du tout.
    Le propos n'est pas de dire que l'on ne peut pas gérer correctement les erreurs avec une approche style C, mais que les exceptions sont un outil puissant, qu'il est dommage de mettre de côté pour de mauvaise raison (petit à petit, on voit que le code C pour gérer correctement les exceptions n'est pas aussi simple que cela, l'argument de la lourdeur des exceptions ne tient plus trop).

    L'autre problématique difficile à gérer avec les retours d'erreur est la gestion du contexte de traitement des erreurs.
    Si on reprend mon exemple de lecture asynchrone et qu'une erreur se produit, on va devoir faire le ménage (appeler le thread pool pour stopper les traitements en cours, appeler les data caches pour supprimer les données inutiles, etc). On peut s'attendre à ce que le traitement d'erreur ne doit pas être réalisé dans la fonction qui a lancé le traitement qui produit une erreur (il serait en effet étonnant qu'une même fonction ait accès à autant d'éléments, il y aurait un problème de conception).
    Il faut donc remonter l'erreur dans la pile d'appel des fonctions, jusqu'à revenir sur une fonction capable de gérer cette erreur.
    Avec un retour d'erreur, cela implique de mettre en place le code de gestion des erreurs dans chaque fonction appelée. Cela alourdi le code, surtout que le but est simplement de transmettre les erreurs (ie pourquoi écrire un code de gestion d'erreur dans une fonction qui ne fait ni lancer cette erreur, ni la traiter ?)
    Avec les exceptions, l'erreur va naturellement remonter la pile d'appel, jusqu'à une fonction qui saura la gérer (ou jusqu'à la fin du programme, si on n'a pas ou si on ne sait pas gérer cette erreur).

    Les bénéfices d'une (bonne) gestion des erreurs par exceptions ne sont pas négligeable.

  7. #27
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    On revient donc à ce que j'ai dis, utilisé les exception pour une erreur grave empêchant la bonne continuation du programme, et les retours d'erreur pour les erreur mineur, lorsque ça n’empêche pas le programme d'avancer .
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  8. #28
    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
    Concernant TU et assertions.

    Les assertions sont un outil d'investigation des erreurs de programmation de type non respect de contrats. Cet outil s'utilise en phase de tests (qui tournent en debug!) -- et avec un peu de chance un jour cela sera exploité par des outils d'analyse statique de code. Qu'ils soient TU, TI, TV, test du singe, ..., OSEF. S'il y a une rupture de contrat, alors les assertions vont nous aider à investiguer le contexte qui a conduit à cette erreur.
    Les assertions ne sont cependant pas terriblement adaptées pour les post-conditions. Les post-conditions simples, c'est cool (genre sin(x) <= 1), mais les conditions complexes, c'est moins évident (genre que sin(x) renvoie bien sin(x) et pas autre chose qui vérifie des propriétés faciles à vérifier). C'est là qu'interviennent les TU : ils seront bien mieux adaptés.

    Maintenant, dumper un core depuis un (exécutable de) TU va effectivement parasiter les métriques si le TU contient plusieurs tests. C'est ici qu'intervient la série de propositions d'évolution du C++ par John Lakos : il propose un framework qui permet de choisir la politique comportementale des assertions. Et donc de lever des exceptions pour les TU qui sont lancés automatiquement en intégration continue (CDash & cie). Et il reste possible qu'en cas d'exception de logique de rebasculer en mode core-dump pour pouvoir investiguer les contextes -- chose que les exceptions (normalement utilisées) ne permettent pas.

    NB: on devrait tous être d'accord sur le fait que tester directement les préconditions de fonctions dans des TU est idiot et une perte de temps. Un non respect de précondition est une UB, on n'a pas besoin d'en savoir plus. En revanche, tester des fonctions qui en appellent d'autres sans en respecter les contrats a parfaitement du sens (en supposant que le non respect de contrat soit un hasard, i.e. une erreur involontaire)

    Comme le disait mintho carmo, je me suis étendu sur le sujet des contrats dans deux de mes billets de blog (le troisième est en finalisation depuis quelques mois ^^'), premier lien de ma signature.

    BTW, mintho carmo, ta traduction de narrow est tellement évidente que je me demande comment j'ai pu passer à côté ^^'



    Citation Envoyé par skeud Voir le message
    a- Personnellement j'utilise les exception dans le cas d'erreur critique (ne pouvant conduire à une bonne exécution de la suite du programme, comme un pointeur vide, ou de mauvaise donnée d'entrée).

    b- Et le retour d'erreur quand c'est juste un ptit warning (donnée non présente, mais ne bloquant pas le programme).

    c- Ensuite le gros avantage des exceptions est de pouvoir retrouvé l'origine (ie endroit du code qui a soulevé l'exception). Sauf qu'en cas d'exception lever, avec une mauvaise gestion, il est facile de sauter des parties du workflow, et donc de conduire à des problèmes, c'est souvent pour cette raison que les exception sont pas très conseillées.
    a- Cela n'est pas le rôle des exceptions. Enfin, des std::logic_error en mode Programmation Défensive éventuellement, mais elles s'intègrent généralement assez mal avec des programmes classiques (qui ont des [minicode]catch (std::exception const&)[/minicode] aux points d'interfaçage).
    Le meilleur outil qui soit pour détecter les erreurs de contrat, ce sont les assertions. Cf mes billets de blog donc.

    b- En quoi une exception serait incompatible avec une erreur de contexte ? Elles permettent de remonter facilement au point où l'on peut reprendre.
    Si maintenant, c'est une erreur de contexte hyper classique. Il faut peut-être se poser la question de pourquoi cette erreur de contexte est si classique qu'elle en devient banale -- typiquement, boost::lexical_cast<> ne devrait pas être utilisé pour autre chose que valider des entrées (en plein milieu d'un programme, sur une entrée non encore validée, on va se retrouver avec une exception pauvre en information -- cf mes billets de blogs pour voir ce que j'entends pas "pauvre en information").

    c- Tu arrives à retrouver le contexte soit parce que tu as le bon réflexe de lever une std::logic_error et que leur catch est désactivé en debug, ou bien plus probablement parce que ton code ne gère pas les exceptions et ne doit pas contenir beaucoup de catchs. Un code robuste (oserai-je dire de qualité industrielle) rattrapera les exceptions. Et de fait ta feinte ne marchera plus. Heureusement, il restera l'outil ad'hoc : les assertions.


    Perso, je trouve qu'écrire un code correct/robuste et tutti quanti dans un monde à retour de codes d'erreur est trop complexe. On se retrouve vite avec des bêtes totalement in-maintenables qui doublent ou triplent la quantité de code utile comparé à un code à exceptions. Il faut juste comprendre qu'avec les exceptions:
    - on lève là où l'on détecte les erreurs
    - on utilise le RAII pour nettoyer derrière nous
    - et on attrape uniquement là où l'on saura faire quelque chose de l'erreur de contexte (log, proposer à l'utilisateur de recommencer, de vérifier sa connexion, de corriger son fichier buggué, ...).
    - on laisse la propagation sur tous les niveaux intermédiaires au C++/compilateur qui fera un bien meilleur boulot que celui que nous aurions fait en propageant tout à la main (moins de risque d'erreurs suite à l'explosion de la complexité cyclomatique, et probablement de meilleures perfs vu qu'il n'y aura plus un branchement toutes les deux lignes (je suppose naïvement que les codes ne sont pas écris au pays magique où les erreurs n'existent pas vu que vous semblez vous placer dans ce contexte.

    Dit autrement, comparez les deux codes à la fin de cet article (que mintho carmo a cité plusieurs fois, mais que personne n'a du ouvrir): http://alexandre-laurent.developpez....ou-exceptions/. Si votre code source reposant sur des codes de retour ne ressemble pas à celui de gauche (ou à un équivalent avec gotos), c'est qu'il est faux. S'il y ressemble, vraiment vous préférez écrire et maintenir ce type de code à celui de droite ?
    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...

  9. #29
    Rédacteur/Modérateur

    Avatar de yahiko
    Homme Profil pro
    Développeur
    Inscrit en
    Juillet 2013
    Messages
    1 423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 1 423
    Points : 8 700
    Points
    8 700
    Billets dans le blog
    43
    Par défaut
    J'espère que personne ici ne conteste l'utilité des exceptions.

    Il faut simplement savoir que selon le langage employé deux cas peuvent se présenter.

    * Soit elles existent comme dans la quasi totalité des langages post 1990's, et dans ce cas il vaut mieux les utiliser.

    * Soit elles n'existent pas comme en C pour ne citer que lui et dans ce cas il faut faire autrement, par code retour, parce qu'il n'y a pas de magie.
    Tutoriels et FAQ TypeScript

Discussions similaires

  1. Le langage Java est-il adapté pour les jeux vidéo ?
    Par Invité dans le forum Développement 2D, 3D et Jeux
    Réponses: 637
    Dernier message: 05/02/2021, 22h38
  2. La dématérialisation des supports a-t-elle de l'avenir pour les Jeux-vidéos ?
    Par raptor70 dans le forum Développement 2D, 3D et Jeux
    Réponses: 45
    Dernier message: 12/04/2011, 11h01
  3. Réponses: 0
    Dernier message: 01/09/2009, 11h00
  4. Résolution des images pour les jeux vidéos
    Par YuGiOhJCJ dans le forum Développement 2D, 3D et Jeux
    Réponses: 4
    Dernier message: 04/04/2006, 12h24

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