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

Qt Discussion :

Comprendre la gestion facile de mémoire par Qt - fuite de mémoire


Sujet :

Qt

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    bruce-willis
    Invité(e)
    Par défaut Comprendre la gestion facile de mémoire par Qt - fuite de mémoire
    Bonjour les amis !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <qlcdnumber.h>
    #include <qslider.h>
     
    #include "mywidget.h"
     
    MyWidget::MyWidget( QWidget *parent, char *name ) : QVBox( parent, name )
    {
      QLCDNumber *lcd = new QLCDNumber( this );
      QSlider *s = new QSlider( QSlider::Horizontal, this );
     
      connect( s, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) );
    }
    La plupart des programmeurs de C++ réagiront à ce code, nous faisons un new, mais aucun delete. Il est fait par la classe de base de laquelle nos widgets sont dérivés. Mais je ne comprends pas, comment ? Je pense pas que MFC de Visual C++ ne permet pas de faire ça, donc c'est une spécificité de Qt ?
    QMyObject est ici une classe héritant QObject, pourquoi mon code provoque une fuite de mémoire tandis que mon second n'en fait pas :
    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
    int main( int argc, char **argv )
    {
      // Create an application
      QApplication a( argc, argv );
     
      // Create instances
      QMyObject top( 0, "top" );
      QMyObject *x = new QMyObject( &top, "x" );
      QMyObject *y = new QMyObject( &top, "y" );
      QMyObject *z = new QMyObject( x, "z" );
     
      // Do stuff to stop the optimizer
      top.doStuff();
      x->doStuff();
      y->doStuff();
      z->doStuff();
     
      return 0;
    }
    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
    int main( int argc, char **argv )
    {
      // Create an application
      QApplication a( argc, argv );
     
      // Create instances
      QMyObject top( 0, "top" );
      QMyObject *x = new QMyObject( 0, "x" );
      QMyObject *y = new QMyObject( 0, "y" );
      QMyObject *z = new QMyObject( x, "z" );
     
      // Do stuff to stop the optimizer
      top.doStuff();
      x->doStuff();
      y->doStuff();
      z->doStuff();
     
      return 0;
    }

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par bruce-willis Voir le message
    QMyObject est ici une classe héritant QObject, pourquoi mon code provoque une fuite de mémoire tandis que mon second n'en fait pas :
    Bonjour,
    pourquoi dit tu que tu as une fuite memoire???

    Pour les delete, c'est Qt qui s'en charge. Lors de la création d'un objet Qt,il y as toujours un parent associé qui va géré la vie de cette objet

  3. #3
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Citation Envoyé par Matthieu Brucher
    Dans un code Qt4, on verra souvent un new sans delete associé.

    En fait, si une nouvelle instance de QObject est crée et qu'on lui spécifie un parent - le premier argument du constructeur -, c'est ce parent qui sera chargé de la destruction du fils.

    La majorité des classes de Qt4 hérite plus ou moins directement de QObject, mais attention, ce n'est pas le cas de toutes. L'indicateur est la possiblité de passer un objet parent au constructeur.

  4. #4
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    Le parent détruit ses enfants.
    Un enfant détruit se désenregistre de son parent dans le destructeur.
    Si tu détruits le parent, il va détruire en cascade ses fils.

    Ce qui explique pourquoi le code suivant pose probleme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      QMyObject *top = new QMyObject( 0, "top" );
      QMyObject x ( top, "x" );
      delete top; // provoque un delete x...

  5. #5
    bruce-willis
    Invité(e)
    Par défaut
    Salut tout le monde !

    Donc si je retiens bien, un composant Qt déclaré dans une classe Qt doit avoir this comme paramètre pour pouvoir être détruit sans delete.

    Que se passe-t-il si je mets un delete dans le destructeur de la classe pour désallouer le composant ?

  6. #6
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    J'ai pas compris ta phrase

    La regle est simple:
    S'il y un new, il faut un delete
    Dans le cas de Qt, il y a ce post scriptum:
    Qt effectue automatiquement un appel de delete pour les classes contenues dans un conteneur
    Donc toutes tes classes Qt que tu crées avec un parent, elles seront automatiquement détruites via un appel a delete.

    Probleme: dans l'exemple que je donne, volontairement tordu, la classe x n'a pas été allouée avec new, donc d'apres la 1ere regle ci dessus il ne faut pas faire de delete. C'est équivalent au code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    QMyObject x;
    QMyObject *p_x = &x;
    delete p_x; // aie!
    Si tu désalloues toi meme un composant, ce composant va se désenregistrer de son conteneur, et donc le conteneur n'essaiera pas de le détruire une deuxieme fois. Voici un exemple:
    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
    24
    25
    26
    class MyWidget : public QWidget
    {
    public:
        MyWidget():
            button4( this ),
            button5( 0 )
        {
             button1 = new QPushButton( this );
             button2 = new QPushButton( 0 );
             button3 = new QPushButton( this );
        }
     
        ~MyWidget()
        {
             delete button1; // facultatif
             delete button2; // obligatoire
             // button3 sera détruit par Qt dans le destructeur de QObject
        }
     
    private:
        QPushButton *button1;
        QPushButton *button2;
        QPushButton *button3;
        QPushButton button4;
        QPushButton button5;
    };
    button1: alloué avec new, en donnant un parent Qt. Du coup si je n'avais pas appelé moi meme delete dans le destructeur de ce parent, il aurait quand meme été effectué un tout petit peu plus tard dans le destructeur de QObject (je crois), exécuté une fois que ~MyWidget(), ~QWidget, etc... aient été exécuté.
    Qt ne fera pas un double "delete button1", parce que button1, quand il est détruit, va "s'enlever" de MyWidget.

    button2: il n'a pas de parent, donc Qt n'a aucun moyen de savoir quand le détruire, donc il ne le fera pas. Il faut donc soi meme faire un delete.

    button3: idem que button1, sauf que cette fois on laisse Qt effectuer le delete

    button4 et button5: sont des objets membres de MyWidget. C++ va automatiquement les détruire quand MyWidget est détruit. Ces objets vont alors "s'enlever" de MyWidget, et MyWidget n'essaiera donc pas de faire un delete dessus.

Discussions similaires

  1. Gestion de la mémoire par Qt
    Par Kaluza dans le forum Qt
    Réponses: 16
    Dernier message: 31/08/2011, 15h48
  2. Réponses: 2
    Dernier message: 12/09/2010, 20h29
  3. Gestion de la mémoire par la VM
    Par sloshy dans le forum Général Python
    Réponses: 3
    Dernier message: 13/09/2009, 03h14
  4. Gestion images opencv python par mémoire partagée
    Par Tchef dans le forum Bibliothèques tierces
    Réponses: 0
    Dernier message: 12/08/2009, 15h12
  5. Gestion de la mémoire par jonas
    Par DevServlet dans le forum JOnAS
    Réponses: 2
    Dernier message: 13/01/2009, 18h01

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