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 :

Cherche Plombier pour bonne fuite Mémoire!


Sujet :

C++

  1. #1
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut Cherche Plombier pour bonne fuite Mémoire!
    Bonjour,

    Je travaille actuellement sur un petit projet scolaire en C++ mais je rencontre des problèmes sur celui-ci qui ne sont pas d'ordre syntaxique. Je pense donc que le code produit une fuite mémoire mais je n'arrive pas à la localiser.

    Je travaille actuellement sur Code::Blocks 8.02 et avec GCC (tout est correctement installé et tourne parfaitement sur d'autre projets). Ci-joint le code et le projet au format CBP. En fait, si une âme charitable voulait bien relire ce code s'il vous plait car je suis vraiment à court d'idée...

    But du programme
    Recherche de pattern oscillant dans les automates cellulaires (pour l'instant : B3S23 le jeu de la vie) selon un algorithme 'Brut Force'. Les tables sont compressé en 1 booléen pour 1 bit (système de masque binaire etc...).

    Symptômes
    Fichiers log.cpp et log.hpp : j'ai essayé de refaire un log façon
    C++ histoire de... Malheureusement la spécialisation de l'opérateur ++ lève une erreur du linker "Multiple definition of..." je pense que l'inclusion des headers peut être en cause bien qu'ils soient protégés, enfin je crois...
    Fichiers Table.hpp et Table.cpp : normalement ici tout fonctionne, à vérifier quand même...
    Fichiers Handler.hpp et Handler.cpp : ici c'est toute la gestion du programme. La cause des problèmes est peut être l'allocateur de Table bien qu'il me semble être correct...

    A la compilation : aucune erreur.
    En utilisant le debugger : le programme se finit normalement, aucun segfault/sigsev.
    Au cours du programme : des adresses NULL confondues avec des adresses
    correcte (en utilisant ==) : cf le fichier généré log.txt.

    Je vous remercie d'avance...
    Fichiers attachés Fichiers attachés

  2. #2
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut
    Début de correction des bugs : il sembleraient que l'inclusion de "./MainHeader.h" à partir de n'importe quel fichier cpp génère les "Multiple definition of..." mais je ne sais pas pourquoi...
    Si quelqu'un a une idée...

  3. #3
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2006
    Messages : 366
    Points : 444
    Points
    444
    Par défaut
    Hello,

    Pour ton problème de fuite mémoire tu devrais essayer de brancher le gestionnaire mémoire du tutoriel de conception d'un moteur 3D de Laurent Gomilla, ça devrait te donner un point de départ sur les ressources non libérées.

    edit : j'avais pas fait attention que ta classe Log n'est pas template, donc ma première remarque ne tient plus, je l'ai supprimée.

  4. #4
    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,

    Pour commencer, je vais me permettre quelques remarques au sujet de ta class log...

    Un petit rappel, d'abord: les définitions des fonctions template doivent se trouver dans les fichiers d'en-tête.

    Ensuite, il semblerait de bon ton d'éviter la copie des objets que tu passe à l'opérateur << de ta classe log...

    L'idéal étant de fournir une référence constante vers ces différents objet.

    Ainsi, le constructeur serait bien plus à son aise sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    LoG(const std::string& filename)
    et ta surcharge de operator<< le serait également sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<typename TYPE>
    LoG& operator<<(const TYPE& obj);
    Ainsi, la seule spécialisation partielle sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<>
    Log& Log::operator<< <std::string>(const std::string& obj)
    {
        log_list.back() += obj;
        return (*this);
    }
    suffirait-elle (grace au constructeur de la classe std::string qui prend un ... const char*) à travailler aussi bien avec une std::string qu'avec ... un const char*

    Pour les autres spécialisations partielle, bien qu'il n'y ait que peu d'avantages à travailler sur des références constantes vers des types primitifs, cela ne fait pas de tort pour autant, donc... autant en profiter

    Ensuite (au fait, pour permettre la compilation de handler.cpp, il faut inclure le fichier d'en-tête <cstring> pour disposer de memcpy ).

    Ainsi, la définition de la méthode void TABLE::reclip_me(void), m'incite à plusieurs remarques:
    i et j sont des compteurs de boucle... l'idée générale étant de déclarer les variables quand on en a besoin, leur déclaration pourrait très bien se faire directement dans la boucle sous les boucles sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for(int j=0; j<h; j++)
    {
        for(int i=0; i<w; i++)
        {
    De plus, et je ne fais ici qu'émettre un avis personnel (que beaucoup partagent d'ailleurs), si le langage accepte les listes de déclarations de variables de même type en les séparant par des virgules, l'idée générale est que le code est bien plus souvent lu qu'il n'est écrit, et que, bien que cela permette de gagner quelques (dixièmes de) secondes lors de l'écriture du code à utiliser cette possibilité, il est préférable de malgré tout veiller à ne faire qu'une déclaration de variable par ligne.

    Tu peux de toutes manières faire confiance au compilateur pour optimiser un code qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int Xmin;
    int Xmax;
    int Ymin;
    int Ymax;
    mais tu évite le risque qu'un lecteur un peu distrait ne remarque pas tout de suite qu'il s'agit de... 4 déclarations

    En outre, il faudrait que tu sois attentif à gérer les différents avertissement lancés par le compilateur quand il est bien réglé:

    Les avertissements ne sont pas tes ennemis, bien au contraire...

    Ils t'indiquent que tu prend un risque, malgré le fait que ton code est syntaxiquement correct.

    En réglant ton compilateur sur un mode "paranoïaque", tu obtiendrait les avertissements suivants concernant cette méthode:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    D:\projects\LifeFinder\Source\Tables.cpp||In member function 'void TABLE::reclip_me()':|
    D:\projects\LifeFinder\Source\Tables.cpp|189|attention : 'Ymin' may be used uninitialized in this function|
    D:\projects\LifeFinder\Source\Tables.cpp|188|attention : 'Xmax' may be used uninitialized in this function|
    D:\projects\LifeFinder\Source\Tables.cpp|188|attention : 'Xmin' may be used uninitialized in this function|
    D:\projects\LifeFinder\Source\Tables.cpp|189|attention : 'Ymax' may be used uninitialized in this function|
    qui t'indiquent, tout simplement, que tes différentes variables risque d'être utilisées sans que tu ne les aie initialisées de manière correcte, avec tous les risques que cela peut comporter.

    Comme la solution est relativement simple, autant "blinder" le code de ce coté là: il suffit, pour les *min, de fournir une valeur plus petite que la valeur minimale que tu dois gérer (ici, sans doute plus petite que 0) et pour les *max, une valeur plus grande que celle que tu dois gérer (par exemple MAX_INT)

    Cela pourrait prendre chez toi, étant donné que tu dispose des valeurs v et w, une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int Xmin=-1;
    int Ymin=-1;
    int Xmax=w+1;
    int YMax=h+1;
    Cela aura pour résultat immédiat de t'éviter d'avoir, en plus, à gérer le fait que ce soit ou non le premier passage dans la boucle, et donc de t'éviter le test if(begin), étant donné que tu serait sur que les valeurs correspondantes au début sont de nature à forcer la modification

    De la même manière, si la fonction main() prend des arguments, le premier doit être un int...

    Le prototype de main est donc soit
    t
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int main(int argc, char* argv[])
    {
    }
    Enfin, il faut se méfier de la fonction system, qui n'est absolument pas portable...

    A vrai dire, c'est surtout du au fait que tu n'est absolument pas sur que la commande que tu invoques existe sur les différents système d'exploitation possibles... Et la cas de "pause" est symptomatique: la commande n'existe que sous windows.

    C'est pourquoi, je te conseillerais volontiers de remplacer cette commande honnie s'il en est par l'alternative proposée dans la FAQ

    Bien sur, tout ceci ne fait pas avancer ton problème... Mais, comme ces remarques générales sont de nature à te permettre d'améliorer ta manière de programmer et que mon message devient déjà fort long, je vais te laisser méditer dessus, et essayer de trouver un peu de temps pour observer ton code de manière plus détaillée
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut
    Merci de vos réponses,

    Pour la classe LOG, j'évoque mon problème sur ce message. J'avais commencer en utilisant les références mais les avait supprimées car les spécialisation de char et const char* reçoivent plus souvent des données directes que des variables...

    Ensuite (au fait, pour permettre la compilation de handler.cpp, il faut inclure le fichier d'en-tête <cstring> pour disposer de memcpy ).
    Je suis étonné que le code compile parfaitement sans cette inclusion...peut-être est-il déjà inclut dans le réseau d'en-tête du programme???

    En réglant ton compilateur sur un mode "paranoïaque", tu obtiendrait les avertissements suivants concernant cette méthode:
    Je les obtiens mais ils n'ont pas de valeur...Par contre je ne vois pas comment je puis supprimer le cas de départ (avec le booléen begin). Cette fonction à pour but de trouver le plus petit rectangle contenant le motif (+1 ligne et +1 colonne de marge de chaque côté...)...Si je lui spécifie la région entière, la fonction sera incapable de trouver cette zone...Donc pour le moment j'initialise à 0 mais je laisse le cas de départ...

    Pour main et reprenant l'expression d'un autre posteur du forum, j'ai eu une longue période d'infidélité...

    Enfin pour system, je l'enlève, je n'en ai pas forcément besoin...

  6. #6
    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
    Citation Envoyé par TNT89 Voir le message
    Merci de vos réponses,

    Pour la classe LOG, j'évoque mon problème sur ce message. J'avais commencer en utilisant les références mais les avait supprimées car les spécialisation de char et const char* reçoivent plus souvent des données directes que des variables...
    Sauf que, à bien y réfléchir, un const char et un const char* se marient très bien avec une const std::string&
    Je suis étonné que le code compile parfaitement sans cette inclusion...peut-être est-il déjà inclut dans le réseau d'en-tête du programme???
    J'ai pourtant utilisé ton fichier de projet code::blocks, et il m'a gentiment jeté à la compilation sous prétexte que memcpy n'était pas déclaré (j'ai du rajouter <cstring> pour que ca fonctionne )

    Je les obtiens mais ils n'ont pas de valeur...
    Si, ils ont une valeur: ils te signalent qu'une variable risque de ne pas être initialisée lorsque tu voudra l'utiliser, car les différentes valeurs se présentent dans une partie de test qui peut ne jamais être effectuée, et ce, même si tu force le passage dans cette partie du test...

    Ce qui démontre, justement, le problème d'algorithme que je m'apprête à te attaquer
    Par contre je ne vois pas comment je puis supprimer le cas de départ (avec le booléen begin). Cette fonction à pour but de trouver le plus petit rectangle contenant le motif (+1 ligne et +1 colonne de marge de chaque côté...)...Si je lui spécifie la région entière, la fonction sera incapable de trouver cette zone...Donc pour le moment j'initialise à 0 mais je laisse le cas de départ...
    Hé bien, voyons un peu le raisonnement que tu suit:
    • Tu déclares tes variables, et, parmi elles, tu défini begin à vrai.
    • tu rentre dans tes boucles imbriquées et tu effectue ton test pour savoir si elle est vivante (au passage, l'écriture du test sous la forme de if( get(i, j)==true) serait peut etre plus lisible... j'aime bien les codes où les choses sont clairement explicites )
    • Si elle est vivante, tu teste si begin est toujours à vrai, et si oui:
      • tu fournit les valeurs à Xmin, Xmax, Ymin et Ymax
      • tu assigne enfin la valeur false à begin.
    • sinon
      • tu vérifie si i est plus petit que Xmin (tu assigne i à Xmin si c'est le cas)
      • tu vérifie si i est plus grand que Xmax (tu assigne i à Xmax si c'est le cas)
      • tu vérifie si j est plus petit que Ymin (tu assigne j à Ymin si c'est le cas)
      • tu vérifie si j est plus grand que Ymax(tu assigne j àYmax si c'est le cas)
    • tu termine ta gestion

    Moi, ce que je te propose, c'est tout simple: initialise d'office tes variables à des valeurs dont tu sais pertinement bien qu'elles devront être modifiées...

    C'est à dire - me culpa, j'ai inversé les valeurs à fournir - que tu dois donner une valeur à tes minima plus grande que la plus grande des valeurs que tu risque de rencontrer et à tes maxima, une valeur plus petite que la plus petite des valeurs que tu peux rencontrer...

    Ainsi, tu es sur que tes variables seront d'office correctement initialisées

    Comme, de toutes manière, les valeurs correspondant à Xmin et Xmax seront évaluées entre 0 et w et que les valeurs correspondant Ymin et Ymax seront évaluées entre 0 et h, il te suffit d'initialiser Xmin à plus que w, Xmax à moins que 0, Ymin à plus que h et Ymax à moins que 0...

    Ainsi, le code peut devenir
    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
    int Xmin = w+1; //+1, ca suffit pour etre "plus grand" que le plus grand ;)
    int Xmax = -1; //-1 suffit pour etre "plus petit" que 0 ;)
    int Ymin = h+1; //quoi, tu ne m'as pas compris la première fois ??? :D
    int Ymax = -1; //idem
    for(int j=0;j<h;++j)
        for(int i=0;i<w;++i)
        {
            if( get(i, j)==true ) //j'aime les code verbeux :D
            {
                /* meme la première fois que les boucles seront effectuées, nous
                 * sommes sur de passer dans les quatre tests
                 */
                if(i<Xmin)
                    Xmin = i;
                if(i>Xmax)
                    Xmax = i;
                if(j<Ymin)
                    Ymin = j;
                if(j>Ymax)
                    Ymax = j;
            }
        }
    } 
    /* suite de la méthode */
    Le résultat est quadruple:
    1. tu as moins de lignes de code, ce qui facilite la lecture
    2. Le compilateur est content, car toutes tes variables sont correctement initialisées
    3. tu supprime une variable devenue inutile
    4. tu supprime un test devenu inutile, et tu gagne donc en performances à l'exécution (il s'agit ici d'une optimisation qui n'a rien de pré maturée )

    Bref, tu gagne sur tous les tableaux
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut
    Oui, effectivement, je n'avais pas penser à croiser les valeurs .
    Merci .

    Par contre je ne comprends toujours pas pour le memcpy. CodeBlocks ne me jetais pas sur le programme que j'ai envoyé...

    Pour le LOG j'ai toujours des "Multiple definitions" si j'essaye de compiler avec les templates...

  8. #8
    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
    Citation Envoyé par TNT89 Voir le message
    Oui, effectivement, je n'avais pas penser à croiser les valeurs .
    Merci .
    Ah, ben, oui... mais ca, c'est ce qui fait toute la différence entre réfléchir un peu ou non

    Par contre je ne comprends toujours pas pour le memcpy. CodeBlocks ne me jetais pas sur le programme que j'ai envoyé...
    C'est peut être propre à ma situation personnelle: je travaille avec gcc 4.3.0
    Pour le LOG j'ai toujours des "Multiple definitions" si j'essaye de compiler avec les templates...
    Déclare ta fonction inline et défini tes spécialisations comme telles
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre confirmé Avatar de TNT89
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Âge : 34

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 615
    Points
    615
    Par défaut
    Ah, ben, oui... mais ca, c'est ce qui fait toute la différence entre réfléchir un peu ou non
    ça fait surtout la différence pendant les DS (Devoirs Surveillés) d'algorithmique...

    Petite question pourquoi je dois forcément passer les spécialisation en inline???

  10. #10
    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
    Citation Envoyé par TNT89 Voir le message
    ça fait surtout la différence pendant les DS (Devoirs Surveillés) d'algorithmique...
    Aussi... je n'osais pas trop aborder ce sujet
    Petite question pourquoi je dois forcément passer les spécialisation en inline???
    Bien, disons, que, normalement, les fonctions template sont de toutes manière inlinée du fait qu'il est impossible de savoir sur quel objet elles vont s'appliquer avant ... de savoir le contexte dans lequel elles sont appelées.

    Le fait de les déclarer explicitement inline permet donc simplement de rappeler au compilateur qu'il doit travailler correctement
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Fuite mémoire cherche plombier
    Par Slurp_student dans le forum C
    Réponses: 2
    Dernier message: 20/07/2011, 12h31
  2. [C++] Logiciel détection fuite mémoire pour Windows
    Par Aspic dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 10/12/2010, 18h49
  3. Réponses: 19
    Dernier message: 04/10/2006, 16h53
  4. [Fuites mémoire] Je cherche un utilitaire
    Par 10_GOTO_10 dans le forum C++Builder
    Réponses: 8
    Dernier message: 10/02/2005, 10h03

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