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 :

Problème sur un destructeur


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 46
    Par défaut Problème sur un destructeur
    Bonsoir à tous,

    Je ne comprends pas mon erreur... Comme je débute, je sollicite vos lumières.
    J'ai une classe qui contient un tableau déclaré et initialisé comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    float* _tab;
    _tab = new float(n);
    Logiquement le destructeur de la classe contient ceci:
    Et pourtant à l'utilisation j'ai une erreur. En effet, à l'utilisation de la classe j'utilise un vecteur (vector) de celle-ci. J'obtiens un crash du programme (la compilation ne pose pas de problème) à partir du deuxième push_back.

    Voici un exemple minimaliste qui reproduit mon problème:
    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #pragma once
     
    class C01
    {
    public:
    	C01(void);
    	~C01(void);
     
    protected:
    	float* _tab;
    	static int _n;
    };
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include "C01.h"
     
    int C01::_n = 100;
    C01::C01(void) :
    _tab(0)
    {
    	_tab = new float[_n];
    }
    C01::~C01(void)
    {
    	delete[] _tab;
    }
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "C01.h"
    #include <vector>
    using namespace std;
     
    int main()
    {
    	vector<C01> lst;
    	lst.push_back(C01());
    	lst.push_back(C01());
    	lst.push_back(C01());
     
    	return 0;
    }
    J'utilise VC++ 2010 Express. Voici la fenêtre qui pop.
    Nom : Sans titre.png
Affichages : 154
Taille : 31,4 Ko

    Par ailleurs, je me suis rendu compte qu'en supprimant le contenu du destructeur, il n'y avait plus de crash. Cependant je ne suis pas sûr que ce soit une bonne chose. J'ai entendu parlé de risque de fuite de mémoire... (je débute)


    D'avance, merci pour votre aide!

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    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 766
    Par défaut
    Parce qu'il te manque le constructeur par recopie

    Sinon:
    • Tester si sa variable est NULL avant de faire le delete. Même si là, cela ne change rien
    • Ton utilisation de ta liste d'initialisation: mets carrément _tab(new float[_n]).
    • Ne mets pas void pour le passage de paramètre vide. C'est du C++, pas du C.
    • Ne pas nommer avec des tirets bas commençant ou fermants. Même si en théorie ce pseudo-problème est réglé.
    • Ne pas utiliser de protected si cela ne sert à rien.


    Édit: dans ton premier code tu as mis new float(n) au lieu de new float[n]

  3. #3
    Membre émérite

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Si la taille du tableau est connue, on peut tout simplement écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class C01
    {
    public:
     
    private:
        float m_tab[100];
    };
    Ou encore mieux, utiliser un std::array -> std::array<float, 100> tab;Pour ces deux containers l'allocation est gérée automatiquement (pas de new ni delete).

  4. #4
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    et pour un tableau de taille inconnue, utilises plutôt std::vector<float>, qui sera également géré automatiquement (pas besoin de delete, copie déjà gérée).
    Sinon, comme mentionné par foetus ton problème vient de l'absence de constructeur de copie. Le vector va faire des copies lors du push_back. Quand un des tes objets est copié, la copie reçoit une copie du POINTEUR vers le tableau de l'original (comportement de copie par défaut). Quand l'original est détruit le tableau est libéré par le delete du destructeur, mais la copie a toujours son pointeur vers la même zone, qui est désormais invalide. Dès lors, à la première tentative d'utilisation, tu commence les lectures / écritures invalides. Si tu as de la chance ça crashe direct. Sinon, la mémoire a été réallouée, et là ça fait n'importe quoi...
    conclusion 1: si tu gères des pointeurs dans ta classe, il faut redéfinir le constructeur de recopie
    conclusion 2: moins tu gères de pointeurs, mieux tu te portes

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    46
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 46
    Par défaut
    Bonjour à tous et merci de m'avoir répondu.

    J'ai essayé d'implémenter un constructeur par copie, mais sans succès (je l'ai peut être mal fait).
    Voici ce que j'ai:

    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
    #include "C01.h"
     
    // initialisation du nombre d'éléments
    int C01::_n = 100;
     
    // constructeur par défaut
    C01::C01(void) :
    _tab(new float[_n])
    {
    }
     
    // constructeur par copie
    C01::C01(C01& c01) :
    _tab(c01._tab)
    {
    }
     
    // destructeur
    C01::~C01(void)
    {
    	delete[] _tab;
    }
    Malgré cela j'ai toujours le crash.


    Si la taille du tableau est connue, on peut tout simplement écrire :

    Code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class C01
    {
    public:
     
    private:
        float m_tab[100];
    };
    Ou encore mieux, utiliser un std::array -> std::array<float, 100> tab;Pour ces deux containers l'allocation est gérée automatiquement (pas de new ni delete).
    La taille du tableau est connu, mais pour l'utilisation que je veux en faire la déclaration float m_tab[100]; fait sauter la pile. Mon but est de faire un programme de CFD. J'ai l'ambition d'utiliser des tableaux à plusieurs millions d'entrées. On m'a conseillé de déclarer le tableau comme je l'ai fait.


    Par ailleurs, je n'utilise pas vector (je n'ai pas essayé array) car en faisant un benchmark je me suis aperçu que les opérations sur un membre déclaré comme suit float* m_tab = new float[n] étaient plus rapides (et de loin) que sur son homologue vector... Visiblement le temps d'accès aux éléments est plus court, mais comme je débute, je ne veux pas trop avancer de certitude.

  6. #6
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Pas la bonne signature, ton constructeur de copie:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    C01::C01(const C01& c01) :
    _tab(c01._tab)
    {
    }
    du coup en fait tu le le redéfinissait pas, d'où ton problème.

  7. #7
    Membre émérite

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par pingouin84k Voir le message
    Par ailleurs, je n'utilise pas vector (je n'ai pas essayé array) car en faisant un benchmark je me suis aperçu que les opérations sur un membre déclaré comme suit float* m_tab = new float[n] étaient plus rapides (et de loin) que sur son homologue vector... Visiblement le temps d'accès aux éléments est plus court, mais comme je débute, je ne veux pas trop avancer de certitude.
    As tu utilisé un reserve() sur ce vector ? Sinon à chaque(pas vraiment) redimensionnement, il doit réalouer son contenu.

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

Discussions similaires

  1. Problème sur la recherche fulltext en v4 !
    Par poppa dans le forum Requêtes
    Réponses: 3
    Dernier message: 13/05/2004, 23h06
  2. Problème sur fiche MDIchild
    Par nivet dans le forum Composants VCL
    Réponses: 6
    Dernier message: 23/01/2004, 08h07
  3. Problème sur GetPrivateProfileString ???
    Par Bordelique dans le forum Langage
    Réponses: 7
    Dernier message: 25/06/2003, 22h15
  4. Problème sur une requête INSERT
    Par Marion dans le forum Langage SQL
    Réponses: 3
    Dernier message: 17/06/2003, 08h45
  5. problème sur une requête!!!!!
    Par Mcgrady_01 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 13/06/2003, 01h17

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