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 :

Rattraper des exceptions


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    256
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Juin 2002
    Messages : 256
    Points : 121
    Points
    121
    Par défaut Rattraper des exceptions
    Bonjour,

    Je ne suis pas familié de la gestion des exceptions, mais j'essaye de les utiliser. Une question reste, pour moi, en suspens : quelle est la meilleure place pour le bloc try/catch dans un programme win32 ?

    Est-ce dans la CallBack principale ? Dans la boucle "while( GetMessage(...) )" ? Ailleurs ? Où vaut mieux-t-il faire du cas par cas, en plaçant ces blocs de manière locale au même endroit que les exceptions potentielles ??

    merci

    Cordialement
    OS : WinXP
    Outils : VC++ 8 (Visual Studio 2005)

  2. #2
    Membre confirmé Avatar de themadmax
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    446
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 446
    Points : 496
    Points
    496
    Par défaut
    Pour la gestion des exceptions je ne pense pas qu'il existe de difference sinificative en un prog. Win32 et un autre. Les blocs try/catch doivent se trouver ou tu pourras evidement effectué un code tierce pour ta gestion de ton exception. Pour ma philo. : une exception ne sert que pour la gestion des erreures gravent.
    ________________________________________________
    http://bliquid.fr : Blog sur Android et l'Acer Liquid

  3. #3
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    La meilleure place pour un bloc try / catch c'est le premier endroit dans la pile d'appels où l'on peut faire quelque chose de pertinent avec l'exception. Tant que tu n'as rien d'intelligent à faire avec, laisse la remonter.

    Si toutes tes exceptions sont des erreurs fatales et que tu ne veux qu'afficher un message avant de quitter, tu peux très bien te retrouver avec un unique bloc try / catch autour du contenu de ton main (WinMain dans ce cas).

  4. #4
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Pareil que Laurent.
    Pour donner un exemple concret, sur le jeu sur lequel je bosse personnellement j'ai un try a des endroits stratégiques :

    a) dans le main, pour catcher "toutes" les exceptions, de manière à ensuite pouvoir fournir une interface (pour l'instant une boite de dialogue basique) qui permet d'envoyer des informations de debuggage automatiquement sur une boite mail (pour gagner du temps en beta test par exemple) - quel que soit le type d'erreur. J'envoie un fichier de log constitué par les catch suivants...

    b) dans la fonction d'initialisation des systemes de base : le tout est de récupérer les exceptions correspondant à des problèmes de relation software hardware, comme par exemple le cas ou la machine n'a pas les resources nécessaires (carte graphique souvent) pour faire tourner le jeu.
    Je ne fais qu'un log de l'erreur avant de faire throw pour que ce soit intercepté plus haut, au niveau de a)

    c) même chose mais à la libération des resources system (ça peut être de bons indices pour des bugs qui se déroulent pendant le jeu)

    d) un try autour de la boucle principale du jeu, toujours de la même manière, simplement pour logger les exceptions que je connais.

    e) un try lors de l'aquisition du clavier et de la souris : je catch une exception specifique a l'api gérant ces entrées, puis je relance une exception spécifique à mon application derrière avec des infos suplémentaires.


    En revanche, j'ai mis pas mal de temps pour faire en sorte que même si il y a catch appelé, il n'y ai "presque" jamais de mémory leak, même si ça remonte jusqu'au main. On peut penser que c'est inutile puisque l'application va de toutes manières se terminer, mais ça permet aussi de pouvoir plus tard gérer des choses autour de l'application sans souci quand il y a eu un problème grave.

    Mettre en place sa stratégie concernant les exception est important mais surtout a ne pas prendre à la légère.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Dans l'idée, c'est effectivement de traiter l'exception là où tu pourras retomber sur tes pieds. Par exemple, une exception sur une fonction de ton soft peut être traitée par là où elle est invoké pour signalé son échec et permettre à l'appli de continuer à tourner. Une exception amenant à corrompre tes données sera probablement traité à un plus haut niveau et aboutira probablement à l'arrêt du soft ou à la fermeture du document ou une procédure de recouvrement de données, etc... En fait, il est important de se dire: que puis-je faire de cette exception par rapport à l'état du logiciel?

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Points : 1 176
    Points
    1 176
    Par défaut
    ne pas oublier le try...catch( ... ) dans la fonction principale des threads aussi

  7. #7
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    En revanche, j'ai mis pas mal de temps pour faire en sorte que même si il y a catch appelé, il n'y ai "presque" jamais de mémory leak, même si ça remonte jusqu'au main.
    Ça s'appelle l'exception-safety basique.
    C'est absolument automatique si tu programmes en C++ correctement, c'est à dire avec le RAII.
    Boost ftw

  8. #8
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    loufoque> Je suis d'accord, mais parfois c'est loin d'être "automatique", même si on ne fait que du RAII (ce que je fais, dans mon propre code) ...

    Il y a des cas ou le RAII n'est pas "absolu", comme par exemple quand on a une exception déclenchée par une lib , encapsulée auparavant disons, puis un catch qui tente alors de désallouer les resources de la lib en question (via le destructor par exemple) et qui déclenche alors une autre exception, typiquement dépendante d'un cas spécifique issu de la première exception, et du coup certaines resources ne sont pas libérées. Là il faut alors gérer du cas spécifique où du leak est possible, mais dans tous les cas mènera à la fin de l'application (donc potentiellement dans ce cas, moins d'infos de debug par exemple, mais au moins on arrête l'appli).

    Je pense pas que j'ai été très clair....... mais en gros à un certain niveau de complexité, ce n'est pas forcément évident. Surtout quand on manipule des libs externes. (auquel cas le probleme peut bien évidement venir de la lib, mais d'un point de vue de l'utilisateur, c'est votre problème quand même, donc faut gérer plein de trucs suplémentaires, d'où une perte de temps potentielle non négligeable).

    Evidemment, si on a que son propre code, effectivement c'est "absoluement automatique".

    En tout cas, on a pas mieu que la RAII pour gérer tout ça, c'est sur.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je trouve que le terme RAII ne fait pas justice au concept. C'est pourquoi je lui préfère le terme RRIF (Resource Release Is Finalization), beaucoup plus parlant à mes yeux. La preuve:

    Code RAII : 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
    class FichierLecture
    {
    public:
    	FichierLecture(const char *fileName) : m_pfIn(fopen(fileName, "r"))
    	{
    		if(m_pfIn==NULL)
    			throw new std::exception("Echec d'ouverture de fichier");
    	}
    	//Pas de destructeur:
    	//La ressource est leakée,
    	//et pourtant je l'ai acquise lors de l'initialisation!
    	std::string ReadLine();
    	void Close();
    private:
    	FILE * m_pfIn;
    };
    Code RRIF : 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
    32
    class FichierLecture
    {
    public:
    	FichierLecture() : m_pfIn(NULL)
    	{ }
    	//Destructeur présent:
    	//La ressource sera toujours libérée, 
    	//Et pourtant je ne l'ai pas acquise lors de l'initialisation...
    	~FichierLecture()
    	{
    		Close();
    	}
    	std::string ReadLine();
    	void Close()
    	{
    		if(m_pfIn!=NULL)
    		{
    			fclose(m_pfIn);
    			m_pfIn = NULL;
    		}
    	}
    	void Open(const char *fileName)
    	{
    		Close();
    		assert(m_pfIn==NULL); //Close() doit l'avoir remis à NULL
    		m_pfIn = fopen(fileName, "r");
    		if(m_pfIn==NULL)
    			throw new std::exception("Echec d'ouverture de fichier");
    	}
    private:
    	FILE * m_pfIn;
    };
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Il y a des cas ou le RAII n'est pas "absolu"
    Si si. Ça se démontre.

    comme par exemple quand on a une exception déclenchée par une lib , encapsulée auparavant disons, puis un catch qui tente alors de désallouer les resources de la lib en question (via le destructor par exemple) et qui déclenche alors une autre exception, typiquement dépendante d'un cas spécifique issu de la première exception, et du coup certaines resources ne sont pas libérées. Là il faut alors gérer du cas spécifique où du leak est possible, mais dans tous les cas mènera à la fin de l'application (donc potentiellement dans ce cas, moins d'infos de debug par exemple, mais au moins on arrête l'appli).
    Ton exemple est incompréhensible.
    Un destructeur doit être nothrow. Et toute libération de ressource doit se faire dans le destructeur, certainement pas ailleurs (enfin, dans operator= ou dans les constructions de mouvement éventuellement, mais ça peut s'exprimer plus élégamment avec swap)

    @Medinoc:
    Le cas sans état vide est simple. Constructeur : fopen (exception en cas d'échec), Destructeur : fclose. Pas de fonction membre Close.
    Avoir un état vide ne veut pas dire que tu n'es pas conforme au RAII, ça veut simplement dire que les invariants de ton objet sont différents. Je trouve personnellement plus utile de maintenir l'invariant qu'on a toujours une ressource que de permettre d'avoir un objet dans un état vide et avec lequel on ne peut rien faire sans risquer que tout nous pète à la gueule.
    On remarquera d'ailleurs que dans les deux cas il te faut désactiver operator= et le constructeur de copie sous peine d'avoir de gros problèmes.
    Par ailleurs, avec ton second code, si on a déjà une ressource et qu'on tente d'en ouvrir une autre et que cela échoue, on se retrouvera avec plus rien. Super...
    Boost ftw

  11. #11
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Ton exemple est incompréhensible.
    Désolé, je manque de sommeil. C'est un ensemble vraiment complexe et c'est difficile a expliquer.

    Si si. Ça se démontre.
    Je veux bien voir ça.


    Un destructeur doit être nothrow.
    Je ne suis pas d'accord, j'ai un cas ultra rare (unique dans mon experience personnelle) où j'ai un destructeur avec un throw, qui est non seulement utile mais aussi indispensable.

    Et *toute* libération de ressource doit se faire dans le destructeur, certainement pas ailleurs.
    Comme je disais, en théorie je suis d'accord (et c'est ce que je fais dans mon code). Dans la pratique il y a des "cas" (qui sont issues de cas complexes) pour lesquels c'est tout simplement faux.

  12. #12
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    En général, si tu ne peux pas libérer une ressource, il n'y a rien d'intelligent que tu puisses faire à part signaler l'erreur.
    Boost ftw

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Loufoque> Oui! C'est bien ce que je fais, j'ai juste fais mon maximum eviter ce genre de cas et avoir un max d'infos quand on y arrive quand même.

Discussions similaires

  1. Codes d'erreurs des exceptions
    Par dway dans le forum Assembleur
    Réponses: 3
    Dernier message: 08/09/2004, 09h37
  2. [ORACLE 9i] Gestion des exceptions
    Par sygale dans le forum SQL
    Réponses: 6
    Dernier message: 19/08/2004, 15h06
  3. Gestion des exception (EOleException)
    Par shurized dans le forum Bases de données
    Réponses: 5
    Dernier message: 30/06/2004, 17h25
  4. [XMLRAD] gestion des exceptions
    Par pram dans le forum XMLRAD
    Réponses: 2
    Dernier message: 28/01/2003, 17h48
  5. c: gestion des exceptions
    Par vince_lille dans le forum C
    Réponses: 7
    Dernier message: 05/06/2002, 14h11

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