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

Langage C++ Discussion :

Crash à l'appel d'une méthode.


Sujet :

Langage C++

  1. #1
    Invité
    Invité(e)
    Par défaut Crash à l'appel d'une méthode.
    Salut, je possède une classe Button, dans laquelle je défini un bouton, et quelques foncteurs pour appeler une méthode d'une interface lorsqu'on clique sur le bouton ce qui donne ceci ;

    Code cpp : 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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    Button::Button(math::Vec3f position, math::Vec3f size, const Font* font, sf::String t, RenderWindow& rw) :
                    rw(rw),
                    LightComponent(position, size, size * 0.5f,false) {
                    background = sf::Color::White;
                    text.setFont(*font);
                    text.setString(t);
                    text.setColor(sf::Color::Black);
                    text.setPosition(position);
                    text.setSize(size);
                    rect = RectangleShape(size);
                    rect.setOutlineThickness(5.f);
                    rect.setOutlineColor(sf::Color::Black);
                }
                void Button::clear() {
                    rect.setFillColor(background);
                }
                void Button::setTextSize(unsigned int size) {
                    text.setCharacterSize(size);
                }
                void Button::setTextColor(sf::Color color) {
                    text.setColor(color);
                }
                void Button::draw(RenderTarget& target, RenderStates states) {
                    rect.setPosition(getPosition());
                    target.draw(rect, states);
                    target.draw(text, states);
                }
                std::string Button::getText() {
                    return text.getString().toAnsiString();
                }
                bool Button::isMouseInButton() {
                    physic::BoundingBox bb = getGlobalBounds();
                    math::Vec2f mousePos = math::Vec2f(sf::Mouse::getPosition(rw).x, sf::Mouse::getPosition(rw).y);
                    if (bb.isPointInside(mousePos)) {
                        return true;
                    }
                    return false;
                }
                void Button::addActionListener (ActionListener *al) {
                    core::FastDelegate<bool> trigger(&Button::isMouseInButton, this);
                    core::FastDelegate<void> slot(&ActionListener::actionPerformed,al, this);
                    core::Action a (core::Action::EVENT_TYPE::MOUSE_BUTTON_PRESSED_ONCE, sf::Mouse::Left);
                    core::Command cmd(a, trigger, slot);
                    getListener().connect("CBUTTONCLICKED", cmd);
                }

    Cette classe hérite de LightComponent, et la classe LightComponent de la classe component, pour chaque gui on a la possibilité de la rendre in/visible et de dés/activer son contexte de gestion d'événements.

    J'ai aussi ajouter une méthode que l'on peut redéfinir lorsque l'on change la visibilité ou lorsque l'on change l'état du contexte de gestion d'événements propre à la gui :

    Code cpp : 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
     
     int Component::nbComponents = 0;
            void Component::setEventContextActivated(bool activateEventContext) {
                this->activateEventContext = activateEventContext;
                onEventContextActivated(activateEventContext);
            }
            bool Component::isEventContextActivated() {
                return activateEventContext;
            }
            void Component::setVisible (bool visible) {
                onVisibilityChanged(visible);
                this->visible = visible;
            }
            bool Component::isVisible() {
                return visible;
            }
            void Component::onVisibilityChanged(bool visible) {}
            void Component::onEventContextActivated(bool activate) {}

    Les méthodes onVisiblityChanged et onEventContextActivated sont virtuelle.

    Mais j'ai un crash, lors de l'appel à la méthode setVisible :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    void Pong::actionPerformed(gui::Button* button) {
        if (button == m_bPseudo) {
            std::string text = "CONNECT*"+m_taPseudo->getText();
            SymEncPacket packet;
            packet<<text;
            Network::sendTcpPacket(packet);
            std::string response = Network::waitForLastResponse("CONNECTED");
            std::vector<std::string> infos = split(response, "*");
            if (infos[0] == "NOTOK") {
                m_pseudoUsed->setVisible(true);
            } else {
                m_taPseudo->setVisible(false);
                m_bPseudo->setVisible(false);

    Ca crash à cette ligne-ci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    m_bPseudo->setVisible(false);

    Lors de l'appel de la méthode onVisibilityChanged.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #0 0xfffffffffffffff8	?? () (??:??)
    #1 0x45ee46	odfaeg::graphic::Component::setVisible(bool) () (??:??)
    #2 0x43d96f	Pong::actionPerformed(this=0x7fffffffe260, button=0x8a7730) (/home/laurent/Développement/Projets-c++/ODFAEGVIDEOTUTORIAL2/pong.cpp:149)
    #3 0x46534d	std::_Function_handler<void (odfaeg::graphic::gui::ActionListener*&, odfaeg::graphic::gui::Button*&), odfaeg::core::DynamicWrapper<void, odfaeg::graphic::gui::ActionListener, odfaeg::graphic::gui::Button*> >::_M_invoke(std::_Any_data const&, odfaeg::graphic::gui::ActionListener*&, odfaeg::graphic::gui::Button*&) () (??:??)
    #4 0x43584b	odfaeg::core::Listener::processEvents(this=0x8a7930) (/usr/local/include/odfaeg/Core/listener.h:161)
    #5 0x435755	odfaeg::core::Listener::pushEvent(this=0x8a7930, event=...) (/usr/local/include/odfaeg/Core/listener.h:142)
    #6 0x435973	odfaeg::graphic::Component::pushEvent(this=0x8a7730, event=...) (/usr/local/include/odfaeg/Graphics/component.h:19)
    #7 0x436182	odfaeg::core::Application::update(this=0x7fffffffe260) (/usr/local/include/odfaeg/Core/application.h:158)
    #8 0x435c67	odfaeg::core::Application::exec(this=0x7fffffffe260) (/usr/local/include/odfaeg/Core/application.h:77)
    #9 0x435444	main(argc=0x1, argv=-7048) (/home/laurent/Développement/Projets-c++/ODFAEGVIDEOTUTORIAL2/main.cpp:4)
    Bon, je ne comprends vraiment pas en quoi cela peut faire crasher. D'autant plus que je ne fais que de passer une instance d'une classe dérivant de l'interface et l'instance du bouton au foncteur, et ensuite, je récupère le pointeur sur le bouton qui a été cliqué lors de la redéfinition de la méthode virtuelle pure de l'interface. (comme en java)

    Et lorsque je veux rendre un bouton invisible dans cette méthode, ça crash. :/

  2. #2
    Invité
    Invité(e)
    Par défaut
    En résumé, le crash survient quand j'appelle une méthode virtuelle dans une méthode d'un objet passé à un foncteur.

    Sinon, pas de soucis si je met ça en commentaire :

    Code cpp : 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
     
    void Pong::actionPerformed(gui::Button* button) {
        if (button == m_bPseudo) {
            std::string text = "CONNECT*"+m_taPseudo->getText();
            SymEncPacket packet;
            packet<<text;
            Network::sendTcpPacket(packet);
            std::string response = Network::waitForLastResponse("CONNECTED");
            std::vector<std::string> infos = split(response, "*");
            if (infos[0] == "NOTOK") {
                m_pseudoUsed->setVisible(true);
            } else {
                m_taPseudo->setVisible(false);
                //button->setVisible(false);
                m_taPseudo->setEventContextActivated(false);
                //button->setEventContextActivated(false);

  3. #3
    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
    Si onVisiblityChanged n'est pas définie, le problème vient probablement pas de la fonction setVisibility. Du coup, c'est probablement un UB, qui fait crasher le programme n'importe où, mais surtout pas au bon endroit

    Difficile d'aider sans avoir un code minimal qui reproduit l'erreur et sans se pencher sur tout le code en détail (c'est probablement un heisenbug, donc le truc super chia... a identifier. Ou pas, c'est une pure question de chance)

    C'est typiquement le genre de problème que l'on a avec des pointeurs nus valide. La meilleurs solution : évite les pointeurs nus (pointeurs intelligents), vérifie des condition avec des assert (avant chaque utilisation d'un pointeur)

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Si ton code compile mais que les variables button et m_bPseudo plantent à l'appel d'une méthode (ou d'un attribut), cela sent le pointeur supprimé mais pas initialisé à NULL après coup.

    D'autant que button == m_bPseudo

  5. #5
    Invité
    Invité(e)
    Par défaut
    Si onVisiblityChanged n'est pas définie, le problème vient probablement pas de la fonction setVisibility. Du coup, c'est probablement un UB, qui fait crasher le programme n'importe où, mais surtout pas au bon endroit
    onVisibilityChanged est définie...

    Si ton code compile mais que les variables button et m_bPseudo plantent à l'appel d'une méthode (ou d'un attribut), cela sent le pointeur supprimé mais pas initialisé à NULL après coup.

    D'autant que button == m_bPseudo
    Oui, je compare les adresses des boutons pour savoir sur quel bouton on a cliqué.

    Et les pointeurs, ne sont pas supprimé, mon framework gère la mémoire de manière intelligente c'est à dire que j'ajoute mes guis dans un cache, et, les pointeurs sont détruit à la destruction du cache. (c'est à dire tout à la fin de l'application)

    Exactement comme avec le framework Qt.

    Je sens que ce crash va être difficile à déboguer, je vais essayer avec un code plus minimal.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Oui, je compare les adresses des boutons pour savoir sur quel bouton on a cliqué.
    Tu n'as pas compris ce que je voulais dire : tu as un plantage sur le MÊME objet et non pas sur 2 objets distincts.

    Citation Envoyé par Lolilolight Voir le message
    Et les pointeurs, ne sont pas supprimé, mon framework gère la mémoire de manière intelligente c'est à dire que j'ajoute mes guis dans un cache, et, les pointeurs sont détruit à la destruction du cache. (c'est à dire tout à la fin de l'application)
    Que ton objet soit auto-géré, géré à la main, mis en cache, mis dans un bassin, ou je ne sais pas quoi, cette ligne est explicite
    odfaeg::graphic::Component::setVisible(bool) () (??:??).

    Ton pointeur est crasseux qu'il soit détruit, slicé, mal réinterprété ou je ne sais pas quoi

  7. #7
    Invité
    Invité(e)
    Par défaut
    Tu n'as pas compris ce que je voulais dire : tu as un plantage sur le MÊME objet et non pas sur 2 objets distincts.
    Selon toi alors comment pourrais je faire le test pour savoir sur quel bouton j'ai cliqué ?

    En prenant le texte du bouton ?

    Sinon oui c'est bien le même objet. (Le 1er c'est le pointeur this que je passe au foncteur, et le second c'est aussi un pointeur sur cet objet que j'ai alloué avec new)

    En quoi cela pose problème ?

    Que ton objet soit auto-géré, géré à la main, mis en cache, mis dans un bassin, ou je ne sais pas quoi, cette ligne est explicite
    odfaeg::graphic::Component::setVisible(bool) () (??:??).

    Ton pointeur est crasseux qu'il soit détruit, slicé, mal réinterprété ou je ne sais pas quoi
    Détruit et mal ré-interprété je ne pense pas, il est sûrement slicé mais là je ne comprend pas pourquoi.
    Dernière modification par Invité ; 22/02/2015 à 15h20.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Voici un code minimaliste qui reproduit le bug :

    Code cpp : 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
     
    class ActionTest : public gui::ActionListener {
    public :
        void actionPerformed(gui::Button* button) {
            std::cout<<"invisible"<<std::endl;
            button->setVisible(false);
        }
    };
    int main (char* argc[], int argv) {
        RenderWindow window(sf::VideoMode(800, 600), "Test");
        Font font;
        font.loadFromFile("fonts/FreeSerif.ttf");
        ActionTest at;
        gui::Button button(Vec2f(350, 275), Vec2f(100, 50), &font,"Test",window);
        std::function<void(ActionTest*, gui::Button*)> slot = &ActionTest::actionPerformed;
        window.getView().move(window.getSize().x * 0.5f, window.getSize().y * 0.5f, 0);
        while (window.isOpen()) {
            sf::Event event;
            while(window.pollEvent(event)) {
                if (event.type == sf::Event::Closed) {
                    window.close();
                }
                if (button.isMouseInButton() && event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {
                    slot(&at, &button);
                }
            }
            window.clear();
            window.draw(button);
            window.display();
        }
        return 0;

    On dirait que c'est lors de l'appel à l'opérateur() de std::function que mon pointeur est corrompu.

    Si vous voulez le code de la classe Button, il est ci-dessus, mais cette classe hérite de la classe component (les deux dernière méthodes sont virtuelles et par défaut elles ne font rien si elles ne sont pas redéfinie)

    Code cpp : 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
     
     void Component::setEventContextActivated(bool activateEventContext) {
                this->activateEventContext = activateEventContext;
                onEventContextActivated(activateEventContext);
            }
            bool Component::isEventContextActivated() {
                return activateEventContext;
            }
            void Component::setVisible (bool visible) {
                onVisibilityChanged(visible);
                this->visible = visible;
            }
            bool Component::isVisible() {
                return visible;
            }
            void Component::onVisibilityChanged(bool visible) {}
            void Component::onEventContextActivated(bool activate) {}

    Je pense que le crash provient de la classe std::function vu que je ne vois vraiment rien de suspect dans mon code. :/

    PS : Ou alors bug du compilo ?
    Dernière modification par Invité ; 22/02/2015 à 09h27.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Re-salut!

    Bon hé bien j'ai changé de compilateur. (je suis passé de g++-4.9 à clang++-3.5 et ça a résolu le problème.)

    Clang est il une amélioration de gcc ?

    Ou bien ce sont deux compilateur totalement différent ?

  10. #10
    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
    Ce sont deux projets indépendants, mais cela les options de compilation, tu utilises peut être libstdc++ de GCC avec Clang.

    Tu es un peu rapide a partir sur l’idée d'un problème de compilateur, surtout que tu n'as pas un code très clean

  11. #11
    Invité
    Invité(e)
    Par défaut
    J'utilise la librairie standart avec clang en effet.

    Je préfère clang, je trouve que il donne plus de warnings, et les messages d'erreur sont plus clair.

    Sinon oui ça pourrait aussi être une option de compilation qui fait bug mais étant donné que j'utilise les mêmes options de compilation pour les deux compilateurs, je ne pense pas que le soucis vienne de là.

    Vu que l'adresse de ma variable est carrément corrompue avec gcc. :/

    Sinon je trouve que mon code est bien plus clean que ceux des frameworks déjà existant, pas besoin de fichier .moc et autre bidouilles.

  12. #12
    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
    Un fichier moc ne pose pas de problème en termes de qualité du code. Cela complique la chaîne de compilation, mais dans un environnement pro, tu auras probablement une chaîne de compilation avec des tests, de l'analyse statique, de la doc a générer, des installateurs a créer, etc. L'ajout d'une étape ne sera pas problématique.

    Par contre, ne pas gérer correctement les pré conditions posent de gros problèmes de qualite

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 073
    Points : 12 119
    Points
    12 119
    Par défaut
    #2 0x43d96f Pong::actionPerformed(this=0x7fffffffe260
    Là, je vois comme un this bien foireux, genre un déférencement d'un this "nullptr" avec offset négatif pour un chunk entre v_tables pour de l'héritage multiple.

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

Discussions similaires

  1. Appel d'une méthode virtuelles
    Par BIPBIP59 dans le forum C++Builder
    Réponses: 4
    Dernier message: 24/03/2006, 14h00
  2. Réponses: 2
    Dernier message: 29/12/2005, 10h25
  3. Réponses: 2
    Dernier message: 06/12/2005, 09h41
  4. Réponses: 6
    Dernier message: 27/05/2005, 15h43
  5. Comment connaitre l'appelant d'une méthode
    Par Alec6 dans le forum API standards et tierces
    Réponses: 5
    Dernier message: 12/07/2004, 14h51

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