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 :

Exceptions dans le constructeur


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : Algérie

    Informations forums :
    Inscription : Octobre 2005
    Messages : 90
    Points : 66
    Points
    66
    Par défaut [Résolu]Exceptions dans le constructeur
    Bonjour tout le monde!!

    N'ayant pas le temps d'apprendre le C++ correctement, je met les mains directs dans le cambouis, en m'aidant de votre formidable FAQ. Malheureusement j'ai quelque question qui me taraudes et qui sont tellement betes qu'elles n'apparaissent meme pas dans la faq.

    Enfin bref les voici :

    1-J'utilise des exceptions dans mon constructeur, comment je fais pour l'attraper depuis le main? Sachant que si je met la déclaration de la var dans le try elle ne devient plus visible en dehors. Je met tout le main dans le try? c'est pas un peu bizarre?

    2-J'utilise une classe "A" qui contient des objets d'une autre classe "B". Seulement lors ce que je déclare ces objets, je ne connais pas encore les valeurs que je dois passer au constructeur des objets de "B". Ces parametre je les récupere du constructeur de "A". Comment je fais pour appeler les constructeur des objet de "B" depuis celui de "A"?

    3-plus généralement peut-on appeler le constructeur pour réinitialiser un objet? genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MaClass MaVar();
    ... //on effectue quelques op sur MaVar
    MaVar.MaClass();//réinitialiser MaVar

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Août 2003
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 159
    Points : 171
    Points
    171
    Par défaut
    instancier dynamiquement peut faire l'affaire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    MaClass * MaVar =NULL;
    try
    {
     MaVar = new MaClass ;
    }
    catch( ...)
    {
    if(NULL !=MaVar )
    MaVar->MaClass();
    }
     
    //.....

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    1. En théorie, je dirais que tout le code qui utilise ton objet doit être entouré du bloc try. Reste à savoir s'il est normal que le code en question constitue la totalité du main().
    2. Il faut utiliser une liste d'initialisation (exemple à venir)
    3. Non. Mais si ta classe supporte un opérateur d'affectation, tu peux toujours faire maVar = MaClass(); à nouveau: Le constructeur par défaut et l'opérateur d'affectation seront successivement appelés.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Exemple de liste d'initialisation:
    Code C++ : 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
    class B
    {
    public:
    	explicit B(int tata)
    	 : m_tata(tata)
    	{
    	}
    private:
    	int m_tata;
    };
     
    class A
    {
    public:
    	explicit A(int toto, int tata)
    	 : m_toto(toto), m_beta(tata)
    	{
    	}
    private:
    	int m_toto;
    	B m_beta;
    };
     
    int main(void)
    {
    	A alpha(10, 42);
    	return 0;
    }

  5. #5
    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 174
    Points
    1 174
    Par défaut
    La réponse c'est de bien savoir quand utiliser des exceptions et où les ratrapper.

    Déjà oui il te faut un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    try
    { //...
    } 
    catch( const exception & e ) 
    { //..
    } 
    catch( ... )
    {// ...
    }
    Dans le main, ainsi que dans chaque fonction d'entrée d'un thread.

    C'est le comportement de base:

    si une exception est lancée, elle va remonter jusqu'au main et le programme va se terminer ( en indiquant la nature de l'exception avec e.what() ).

    Maintenant, à toi de savoir quelles exceptions sont à intercepter à quel endroit parce qu'elles ne doivent pas amener à la fermeture du programme.

  6. #6
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 279
    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 279
    Points : 11 015
    Points
    11 015
    Par défaut
    (Hum ... Médinoc a trouvé une nouvelle façon pour qu'il n'y ait pas de réponse pendant qu'il saisit la sienne )

    3- Pourquoi la réinitialiser ? Crées-en une autre sur la pile si tu sors de la portée où sa précédente valeur avait du sens. Fais des fonctions, découpe, tout ça.
    (Il est difficile de faire une réponse générale, j'ai assez peu de besoin en objets "réinitialisables")

    Au fait
    déclare une fonction et non pas une variable -> virer les parenthèses.

  7. #7
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    (Hum ... Médinoc a trouvé une nouvelle façon pour qu'il n'y ait pas de réponse pendant qu'il saisit la sienne )

    3- Pourquoi la réinitialiser ? Crées-en une autre sur la pile si tu sors de la portée où sa précédente valeur avait du sens. Fais des fonctions, découpe, tout ça.
    (Il est difficile de faire une réponse générale, j'ai assez peu de besoin en objets "réinitialisables")

    Au fait
    déclare une fonction et non pas une variable -> virer les parenthèses.
    Ben, des exemples d'objets réinitialisables, ça intervient souvent en programmation 3D avec DirectX, quand on utilise des ressources non "managées" et qu'on a des pertes de "device"...

    Il faut alors regénérer ou recharger les ressources (géométrie, etc.) et les renvoyer à la carte graphique.

    J'avoue que moi j'utilisais alors souvent une construction en 2 temps, pour ne pas avoir à utiliser de pointeurs. Maintenant, je sais pas si je ferais comme ça toujours.

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    865
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 865
    Points : 1 069
    Points
    1 069
    Par défaut
    Citation Envoyé par disturbedID Voir le message
    1-J'utilise des exceptions dans mon constructeur, comment je fais pour l'attraper depuis le main?
    En lisant cette question, j'ai pensé à un chapitre du Thinking C++. Certes, je ne réponds pas à ta question, d'autres s'en sont de toutes façons déjà chargés, mais je peux t'encourager à lire ceci, si tu as du temps, http://bruce-eckel.developpez.com/li...=page_2#L1.1.5
    Tu pourras y trouver des éléments qui t'intéresseront voire dans la suite du document à y trouver des solutions à tes problèmes.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : Algérie

    Informations forums :
    Inscription : Octobre 2005
    Messages : 90
    Points : 66
    Points
    66
    Par défaut
    merci pour les reponses, c'est innatendue.
    Donc :
    1-C'est ce que j'utilisais avant luther13 avec à la fin un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaClass MaVraieVar = *MaVar;
    C'est lourd je vais passer vers un try+catch² dans le main. merci pour les propositions.

    2- Médinoc.

    3-pas grave c'était juste un "sucre syntaxique". Je vais crée une fonction membre pour ça.
    ********************************
    Une derniere :

    4-Dans mon constructeur je fais un appelle explicite
    du destructeur juste avant le throw pour libérer les tableau allouer avec des "pointeurs cons". Est ce que le fait d'appeler le destructeur (pour détruire cet objet donc) à l'intérieur d'une mèthode de la class puis de continuer l'execution de la mèthode de cette objet ne cause t'il pas probleme (on ne rie pas s'il vous plais)?


    En tout cas, moi qui croyais que le C++ c'était du C avec des fonctions dans les struct je me prends une belle claque dans la gueule

  10. #10
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par disturbedID Voir le message
    Est ce que le fait d'appeler le destructeur (pour détruire cet objet donc) à l'intérieur d'une mèthode de la class puis de continuer l'execution de la mèthode de cette objet ne cause t'il pas probleme (on ne rie pas s'il vous plais)?
    A la base, un delete this (ou un appel explicite au destructeur, mais c'est bien plus rare); est autorisé pour peu bien entendu qu'on ne fasse plus d'accès à une variable membre non statique de l'objet par la suite.

    Par contre, là, l'objet n'a pas encore été construit, puisque le constructeur n'a pas fini de s'exécuter. Même si je n'ai pas retrouvé dans la norme de texte à ce sujet, ça me semble très louche, et il me semble que ce n'est pas autorisé.

    Enfin qui te dis qu'au moment où tu attrapes l'exception, tu peux effacer les éléments de ton tableau ? Ce sont peut-être encore des pointeurs invalides...

  11. #11
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 279
    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 279
    Points : 11 015
    Points
    11 015
    Par défaut
    Si une exception sort du constructeur, tous les membres construits jusqu'au point de l'exception sont détruits (détruire un pointeur, comme tout autre scalaire (?), étant une no-op), et le destructeur jamais appelé (normal, l'objet n'a jamais été construit).

    Pour moi, si tu rajoutes un appel au destructeur (dans le constructeur) => comportement non déterminé/défini => tout peut arriver, en particulier, rarement du bon.
    Cf FAQ C++, chapitre sur le RAII, lien sur The big rule of Two qui est très bien sur ce sujet.

    (Et non, le C++ est bien différent (c'est relatif, hein?!) du C. On le voit bien sur tous ces aspects)

  12. #12
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Points : 1 051
    Points
    1 051
    Par défaut
    On m'a dit (mais je ne trouve rien sur le net pour appuyer) qu'un catch avec ellipsis dans un programme sous windows empechait celui ci d'etre certifié microsoft.

    Quelqu'un a plus d'infos ?

  13. #13
    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 174
    Points
    1 174
    Par défaut
    Citation Envoyé par NiamorH Voir le message
    On m'a dit (mais je ne trouve rien sur le net pour appuyer) qu'un catch avec ellipsis dans un programme sous windows empechait celui ci d'etre certifié microsoft.

    Quelqu'un a plus d'infos ?
    J'en sais rien, mais il faut bien que tu empêches toutes les exceptions de remonter ( dans un thread par exemple ).

    Et en C++, n'importe quoi peut être une exception. Donc je ne vois pas comment se passer du ellipsis.

  14. #14
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Je ne sais plus où je l'ai lu (cela devait être sur GOTW), mais je me souviens d'un article disant qu'il ne devait pas y avoir plus d'une ressource non-RAII (pointeur con, sauvegarde d'une valeur à restaurer, descripteur de fichier, etc.) par classe.

    Cela évite les problèmes liés à l'exception dans le constructeur, car seuls les objets déjà construits sont détruits.

  15. #15
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 279
    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 279
    Points : 11 015
    Points
    11 015
    Par défaut
    C'est une règle que j'aime beaucoup sortir. Mais je ne sais plus si c'est mon extrapolation personnelle quant à tout ce qui touche à la gestion de ressources, ou si je l'ai piquée dans l'article sur artima auquel j'ai fait référence dans mon précédent message.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Salut,
    Citation Envoyé par nikko34 Voir le message
    J'en sais rien, mais il faut bien que tu empêches toutes les exceptions de remonter ( dans un thread par exemple ).

    Et en C++, n'importe quoi peut être une exception. Donc je ne vois pas comment se passer du ellipsis.
    De prime abord, je dirais que, si c'est toi qui a créé toutes les classes que tu utilise, tu devrait au minimum savoir les exceptions qu'elles sont sensées lancer en cas de besoin...

    Si tu utilise une bibliothèque externe, tu es sensé t'être documenté un minimum sur les méthodes que tu utilises (et partant, sur les exceptions qu'elles lancent ).

    Si la documentation de la bibliothèque externe ne mentionne pas quelle exception est lancée pour telle ou telle méthode, il est peut être préférable de se tourner vers une autre bibliothèque

    Tout cela pour dire que, normalement, tu ne devrais pas avoir à utiliser l'ellipsis

  17. #17
    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 174
    Points
    1 174
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Tout cela pour dire que, normalement, tu ne devrais pas avoir à utiliser l'ellipsis
    jusqu'au jour où...

  18. #18
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : Algérie

    Informations forums :
    Inscription : Octobre 2005
    Messages : 90
    Points : 66
    Points
    66
    Par défaut
    Citation Envoyé par JolyLoic
    Enfin qui te dis qu'au moment où tu attrapes l'exception, tu peux effacer les éléments de ton tableau ? Ce sont peut-être encore des pointeurs invalides...
    Ils sont initialisés à zéro. Pas de problème donc.

    En tout cas ça marche, si la construction de l'objet échoue, le destructeur est bien appelé (j'ai rajouté un printf à la fin pour vérifier, c'est ok), et la fin du constructeur est exécutée (j'arrive à capturer le throw du main maintenant et afficher le message d'erreur).

    Donc pour moi jusqu'à preuve du contraire, le destructeur n'est qu'une fonction comme les autres (avec un nom qui fait peur), appelée par le compilateur automatiquement quand l'objet sort de la porté ou que delete est appelée.

    Je ne vois pas pourquoi j'aurais à réécrire une deuxième fois le destructeur à l'intérieur du constructeur. Suffit juste de l'appelé ?

  19. #19
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 279
    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 279
    Points : 11 015
    Points
    11 015
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct S {
        S() { p=0; this->~S() ; throw 1; }
        ~S() {delete p;}
        int * p;
    };
    Peut passer si ton compilo et la météo sont gentils avec toi.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct S : T {
        virtual S() { p=0; this->~S() ; throw 1; }
        ~S() {delete p;}
        int * p;
    };
    kaboom.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct S {
        S() : s("toto") { this->~S() ; throw 1; }
        ~S() {}
        std::string s;
    };
    kaboom!
    Indice:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct A {
        ~A() { std::cout << "~A" << std::endl; }
    };
     
    struct S {
        S() { this->~S() ; throw 1; }
        ~S() {}
        A a;
    };
    Le destructeur n'est pas une fonction comme les autres. Et la double destruction de membre ne peut pas se comporter correctement.

    Je ne vois pas pourquoi j'aurais à réécrire une deuxième fois le destructeur à l'intérieur du constructeur. Suffit juste de l'appelé ?
    Parce que ta classe est responsable de plus d'une ressource brute ?
    C'est le prix à payer quand on fait trop de choses.

  20. #20
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : Algérie

    Informations forums :
    Inscription : Octobre 2005
    Messages : 90
    Points : 66
    Points
    66
    Par défaut
    Ok donc
    le destructeur n'est qu'une fonction comme les autres (avec un nom qui fait peur), appelée par le compilateur automatiquement quand l'objet sort de la porté ou que delete est appelée, et qui appelle implicitement les destructeurs des objets membres de la class
    fixed

    (le compile sur le deuxième exemple me dis qu'un constructeur ne peut être virtual).

    Ca tombe bien en tout cas, je suis exactement dans le cas un. (Pas d'objets mebres, que des types de base et des pointeurs cons).

    Pourvu qu'il fasse beau alors

    Parce que ta classe est responsable de plus d'une ressource brute ?
    3 matrices et 2 vecteurs.
    Bon ben sinon j'ajoute une fonction membre partagée avec le destructeur et puis c'est tout. C'est moche mais ça marche.
    Merci en tout cas, cela m'évitera de futures erreurs certaines.

Discussions similaires

  1. Réponses: 5
    Dernier message: 14/05/2008, 20h08
  2. Exception dans le constructeur
    Par olive_le_malin dans le forum C++
    Réponses: 9
    Dernier message: 24/05/2007, 18h02
  3. Réponses: 18
    Dernier message: 28/02/2007, 10h23
  4. exception dans un constructeur
    Par xxiemeciel dans le forum C++
    Réponses: 25
    Dernier message: 23/11/2005, 18h14
  5. Capture d'exception dans un constructeur
    Par declencher dans le forum Composants VCL
    Réponses: 8
    Dernier message: 03/02/2004, 12h52

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