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 :

compilation et exécution ok, mais erreur sous gdb


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 10
    Points : 7
    Points
    7
    Par défaut compilation et exécution ok, mais erreur sous gdb
    Bonjour.
    Je cherche à comprendre pourquoi mon programme pose problème à gdb. La compilation se déroule sans erreur et le programme s'exécute normalement, mais gdb me renvoie un "Debugger finished with status 1" et les points d'arrêt ne fonctionnent pas.

    classe.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #ifndef CLASSE_HPP
    #define CLASSE_HPP
    #include <vector>
     
    const int               array[] = {1, 2, 3, 4};
    const std::vector<int>  vect (array, array + 4);
     
    class MaClasse
    {
        MaClasse();
        ~MaClasse();
        std::vector<int>*    pVect;
    };
    #endif  //CLASSE_HPP
    classe.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "classe.hpp"
     
    MaClasse::MaClasse()
    {
        pVect = new std::vector<int>(4);
    }
     
    MaClasse::~MaClasse()
    {
        delete pVect;
    }
    main.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <iostream>
    #include "classe.hpp"
     
    int main()
    {
        std::cout << "Un simple test..." << std::endl;
        return 0;
    }
    Les sources originales ont été "allégées" pour être présentées sur le forum, ce qui explique l'inutilité des variables globales.


    Le problème disparait si je regroupe tout le code dans un même fichier. Même chose si je supprime les deux variables globales (array et vect dans classe.hpp). Ou bien encore en modifiant l'allocation dynamique dans le constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    pVect  = new std::vector<int>(4); // erreur
    pVect  = new std::vector<int>; // ok
    Voici la copie de la console de gdb :
    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
     
    Building to ensure sources are up-to-date
    Build succeeded
    Selecting target: 
    Debug
    Adding source dir: E:\developpement\CodeBlocks\projet\vecttest\
    Adding source dir: E:\developpement\CodeBlocks\projet\vecttest\
    Adding file: bin\Debug\vecttest.exe
    Starting debugger: 
    done
    Registered new type: wxString
    Registered new type: STL String
    Registered new type: STL Vector
    Setting breakpoints
    Debugger name and version: GNU gdb 6.8
    Child process PID: 3060
    Debugger finished with status 1

    J'ai remarqué que le log détaillé de gdb se terminé par un message inhabituel. A toute fin utile, j'en fournis les dernières lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    > run
    gdb: win32_init_thread_list
    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application's support team for more information.
    [New thread 3252.0x914]
    J'utilise gdb 6.8 avec code::blocks à jour, le tout sous XP.

    Le problème vient-il de mon code ou d'une mauvaise configuration de mingw32? Si quelqu'un peut m'apporter quelques éclaircissements, je suis preneur parce que là, je sèche.

    Merci d'avance.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut, et bienvenue sur le forum.

    Retiens toujours qu'une compilation sans erreur ne signifie nullement que ton code est correct: cela signifie seulement que le compilateur n'a rien rencontré qui déroge aux règles qu'il suit

    De manière générale, il faut éviter l'allocation dynamique d'objet et le recours aux pointeurs si tu n'as pas absolument besoin des possibilités qu'ils offrent (entre autres, au niveau du polymorphisme, ou quand le "contenu" doit survire à la destruction du "contenant").

    Et c'est encore plus vrai avec les classes de la S(T)L

    L'idéal, pour le membre que tu nomme dans ton exemple pVect est donc:
    d'utiliser une valeur plutôt qu'un pointeur
    d'utiliser la liste d'initialisation pour initialiser le membre

    Cela donne au final un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //dans classe_hpp
    class MaClasse
    {
        MaClasse();
        ~MaClasse();
        std::vector<int>    m_vect;
    };
    //dans classe_cpp
    MaClasse::MaClasse():m_vect(vect)
    {
    }
    MaClasse::~MaClasse()
    {
    }
    En effet, la portée des variables fait que la variable est automatiquement détruite lorsque l'on quitte la portée dans laquelle elle a été déclarée, et, au niveau des classes, les membres sont automatiquement créés lorsque le constructeur est appelé (lorsque l'on déclare une nouvelle instance du type de la classe) et détruits lorsque le destructeur est appelé (lorsque l'instance en question est détruite).

    cela signifie que tu que tu as la certitude que, dans le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void fonction()
    {
        MaClasse c1;   //(1)
        for(int i=0; i<10; ++i)
        {
             MaClasse c2;  //(2)
             /*...*/
        }  //(3)
        /*...*/
    }  //(4)
    • les membres de c1 sont construits en 1 et détruits en 4
    • la variable c2 est construite en 2 et systématiquement détruite en 3 (et ce à chaque passage dans la boucle)
    • les membres de c2 sont donc construit en 2 et détuits en 3

    Ceci étant fixé, on pourrait encore te faire valoir:
    • que les variables globales, c'est mal
    • qu'avec la première variable globale Array, il devient inutile de rajouter une variable vect
    • qu'il est sans doute préférable de rendre les membres de ta classe (ici, m_vect, une fois les modifications apportées) privés ou portégés, de manière à éviter de briser l'encapsulation.
    • que l'on est tous d'accord pour "rabâcher" la fameuse rengaine "évitez les tableaux C style et préférez leur les classes du C++"

    Cependant, il ne faut pas se faire plus catholique que le pape non plus - pour ce qui concerne les tableaux- et, si tu sais pertinemment qu'un tableau n'aura jamais qu'un nombre réduit et bien connu à l'avance d'éléments, l'utilisation d'un tableau C style non alloué dynamiquement peut très bien faire l'affaire.

    Ainsi, si tu es sur que ton tableau d'entiers ne contiendra jamais que 4 entiers, ni plus, ni moins, tu peux parfaitement envisager de le déclarer sous la forme toute simple de
    En ce qui concerne les variables globales, on conseille plutôt d'avoir recours à ce que l'on appelle les membres de classe (par opposition aux membres d'instance).

    Ce sont des membres "particuliers" qui font partie d'une classe donnée, mais qui
    1. ne dépendent pas d'une instance particulière de la classe
    2. sont partagés par l'ensemble des instances de la classe

    Pour déclarer un membre de classe, il suffit de faire précéder sa déclaration au sein de la classe par le mot clé static sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    MaClass
    {
        public:
            MaClasse();
            ~MaClasse();
            static /* const */ int array[4];
            std::vector<int> m_vect;
    };
    (tu trouveras la réponse à la plupart des questions que tu peux te poser sur les membres statiques dans la partie de la FAQ qui leur est réservée )
    et, si le seul tableau d'entiers dont tu as besoin est, justement, le tableau statique, tu peux donc sans aucun problème supprimer le membre m_vect

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 10
    Points : 7
    Points
    7
    Par défaut
    Bonjour koala01 et merci pour tes explications, claires et détaillées. A vrai dire je n'en espérais pas autant.

    Tes critiques pertinentes sur mon code, en-dehors de mon problème, sont les bienvenues et j'en prends note. Elles sont autant d'occasions de prendre de bonnes habitudes.

    Si j'ai choisi les vecteurs à la place des tableaux, c'est avant tout pour profiter des méthodes et algorithmes de la STL, cela m'évite de réinventer la roue. De plus, c'est l'occasion de me faire la main sur les vecteurs.

    Quant à l'allocation dynamique, elle me semblait indispensable pour pouvoir faire varier la taille du vecteur au fil du temps. Si j'ai bien compris, cette variation peut tout aussi bien s'appliquer à m_vect. Je vais me documenter sur ce point précis avant d'aller plus loin.

    Au sujet des membres de classe, c'est la solution qu'il me fallait. J'avais déjà abordé cette notion dans des cours mais j'en ai enfin un cas d'utilisation pratique.

    Je vais donc revoir ma copie en tenant compte de tes remarques .

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    En fait, il faut bien comprendre que le d'une classe est de cacher les "détails d'implémentation" (dans le cas de la classe vector, on peut citer le fait qu'il y a surement un T* tab quelque part ) et d'exposer les comportements "qui vont bien" pour la classe en question.

    Ainsi, la classe vector propose plusieurs méthodes parmis lesquelles push_back, push_front et insert dont on se doute qu'elles s'occupent de la gestion dynamique du membre tab (avec (ré)allocation en cas de besoin)

    De la même manière, on se doute que la méthode clear ou que le destructeur va se charger de la désallocation de la mémoire allouée à tab

    C'est la raison pour laquelle il est conseillé d'utiliser, tout simplement, un membre non pointeur quand tu utilise la classe std::vector et de préférer, en cas de nécessité, le passage par référence à... l'utilisation d'un pointeur

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 10
    Points : 7
    Points
    7
    Par défaut
    J'ai apporté les modifications proposées, toutefois mon problème avec gdb restait entier : "Debugger finished with status 1" et points d'arrêt inefficaces.

    J'ai quand même fini par trouver une solution. D'après le log de gdb, le débogueur plante. J'ai donc utilisé gdb en ligne de commande, et isolé la commande à l'origine du plantage : catch thrown. La solution sous Code::Blocks consiste donc à décocher "Catch C++ exceptions" dans Settings->Compiler and debugger...->Debugger settings. A présent, ça roule

    Merci encore à koala01 pour ses conseils.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 15/03/2014, 15h10
  2. ca fonctionne mais erreur compilation déclaration sub
    Par petitours dans le forum VBA Access
    Réponses: 2
    Dernier message: 19/12/2007, 18h30
  3. [PHP-JS] Erreur sous ie mais pas sous ff
    Par ozzmax dans le forum Langage
    Réponses: 6
    Dernier message: 10/07/2007, 17h04
  4. Réponses: 2
    Dernier message: 20/03/2007, 11h50
  5. erreur de requete sous php mais pas sous mysql
    Par kenny49 dans le forum Requêtes
    Réponses: 21
    Dernier message: 28/06/2006, 16h36

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