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

Threads & Processus C++ Discussion :

"pure method called" au test d'un wrapper boost::thread simple


Sujet :

Threads & Processus C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de kidpaddle2
    Inscrit en
    Avril 2006
    Messages
    430
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 430
    Par défaut "pure method called" au test d'un wrapper boost::thread simple
    Bonjour,

    Je viens de synthétiser mon code en créant une classe Thread comme suit :
    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
    class Thread {
    protected:
        boost::thread *m_thread;
     
        virtual void work() = 0;
     
    public:
        Thread() : m_thread(NULL) {}
        virtual ~Thread() {
            catch_up();
            delete m_thread;
        }
     
        inline void catch_up() {
            if(m_thread != NULL) {
                m_thread->join();
            }
        }
     
        void run() {
            m_thread = new boost::thread(boost::bind(&Thread::work, boost::ref(*this)));
        }
    };
    Deux classes en héritent publiquement et implémentent la méthode virtuelle work().
    En transférant des données de l'une à l'autre (les méthodes work() touchent aux données échangées), je me retrouve avec un runtime terminated à cause d'un appel à une méthode virtuelle pure. Je n'en ai qu'une, cela vient donc de work(), mais pourquoi diable appelleraient-ils Thread::work() au lieu de l'implémentation ?

    Edit: Visiblement il y a une affaire de temps derrière... C'est assez aléatoire.

    Merci d'avance.

    Cordialement,

    Kidpaddle2

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Je suppose qu'il n'y a aucun risque que run() soit appelée pendant un constructeur ou un desctructeur?
    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.

  3. #3
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 493
    Par défaut
    "pure method called"
    La Vtable (table des méthodes virtuelles) contient NULL pour la méthode virtuelle appelée. Classiquement, les compilateurs ne remplissent pas la Vtable avant la fin du constructeur de la classe fille, donc un appel de méthode virtuelle dans un constructeur pose en problème car la Vtable n'est pas initialisé.

    Dans le destructeur, c'est pareil.

  4. #4
    Membre éclairé Avatar de kidpaddle2
    Inscrit en
    Avril 2006
    Messages
    430
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 430
    Par défaut
    Merci de vos réponses, mais le problème, c'est que je ne l'appelle pas dans le constructeur...

    J'instancie mes classes dérivées avec le constructeur par défaut, et j'appelle leurs méthodes run() à la suite. D'ailleurs c'est bizarre parce qu'en déboggage, il ne me marque un autre thread d'actif uniquement après le deuxième run()...

    Edit: "Ya pas", en ne mettant que le code suivant, cela fait pareil... Un problème au niveau de la conception, mais où ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    classe A : public Thread {
        void work() {}
    };
    //Et dans le main :
    A a;
    a.run();

  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
    Par défaut
    Citation Envoyé par bacelar Voir le message
    "pure method called"
    La Vtable (table des méthodes virtuelles) contient NULL pour la méthode virtuelle appelée.
    En fait, il existe différente stratégies et en particulier un pointeur vers une fonction d'erreur appropriée (Quelle entrée pour les fonctions virtuelles pures ?).

    Citation Envoyé par bacelar Voir le message
    Classiquement, les compilateurs ne remplissent pas la Vtable avant la fin du constructeur de la classe fille, donc un appel de méthode virtuelle dans un constructeur pose en problème car la Vtable n'est pas initialisé.
    La vtable est construite à la compilation pour chacune des classes contenant des fonctions virtuelles. Ensuite, le vpointeur est initialisé juste avant l'entrée du constructeur pour référencer la table de la classe en cours de construction.
    Citation Envoyé par bacelar Voir le message
    Dans le destructeur, c'est pareil.
    La seule chose que dit la norme, c'est que dans le constructeur/destructeur la fonction virtuelle appelée est celle de la classe en train d'être construite/détruite. Conséquence : certains appels dans le constructeur/destructeur de fonctions virtuelles n'utilisent pas les vtables. (Les appels de fonctions virtuelles pures dans leur classe abstraite est un comportement indéterminé.). Cf tuto Les fonctions virtuelles en C++.


    @kidpaddle2 : héritage == sémantique d'entité == pas de copie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Thread : private boost::noncopyable
    Le cas que je vois pour expliquer ton erreur est que le destructeur a été déroulé et donc le vpointeur désigne la vtable de la classe abstraite. Bref, un problème de durée de vie de variable.

  6. #6
    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
    Par défaut
    En fait, tu penses te prémunir contre la destruction de la variable avant la fin du thread en faisant un join dans le destructeur de Thread. Mais c'est une erreur. Car à ce moment, les destructeurs des classes dérivées ont été déroulés et le vpointeur pointe sur la vtable de Thread. Donc le thread tente d'exécuter le work de Thread qui est une fonction virtuelle pure (et dont l'entrée n'est pas NULL mais vers la fonction d'erreur qui t'affiche le message 'pure function called'.
    Dit autrement, la fin d'exécution du thread ne doit pas être une post-condition de ~Thread mais une précondition. Quand tu arrives dans ce destructeur, le thread doit être terminé.

Discussions similaires

  1. [pure virtual call] erreur d'execution
    Par ZaaN dans le forum C++
    Réponses: 9
    Dernier message: 22/02/2008, 17h32
  2. Réponses: 4
    Dernier message: 17/05/2007, 16h47

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