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 :

Double libération étrange


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Janvier 2009
    Messages : 90
    Par défaut Double libération étrange
    bonjour,

    j'avais ce message lorsque j'additionnais deux matrice "pointer being freed was not allocated" mais après quelque recherche j'ai lu qu'il fallait une méthode de copie et une pour l'operateur = ce qui avait résolu mon problème.

    Mais maintenant lorsque je multiplie deux matrices de tailles inegale une (3,3) par une (3,4) par exemple le calcul s'effectue bien mais j'obtient le message d'erreur "pointer being freed was not allocated"

    le plus étonnant est que lors que je multiplie deux matrice carré de taille n cela marche très bien et je n'ai pas de message d'erreur

    si vous avez une idée d'où vient le problème je serai heureux de le savoir

    voilà mon code de multiplication
    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
    matrice matrice::operator*(const matrice &mat)
    {
    	int i, j, k;
    	matrice nouvellemat(m_ligne , mat.m_colonne);
     
    	//algo de multiplication de matrice qui marche
    	if(m_colonne == mat.m_ligne)
    	{
    		for (i = 0 ; i < m_ligne ; i++)
    		{
    			for (j = 0 ; j < mat.m_colonne ; j++)
    			{
    				for (k = 0 ; k < m_colonne ; k++)
    				{
    					nouvellemat.m_tableau[i][j] = m_tableau[i][k] * mat.m_tableau[k][j] + nouvellemat.m_tableau[i][j];
    				}
    			}
    		} 
    	}
     
    	else
    		cerr << "impossible de multiplier les matrices"<< endl;
    	return nouvellemat;
    }

  2. #2
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Février 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2009
    Messages : 11
    Par défaut
    Je pense qu'il est nécessaire de voir à quoi ressemble ta classe matrice (header et implémentation).

    Il y a peut-être un problème dans le destructeur.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Janvier 2009
    Messages : 90
    Par défaut
    matrice.cpp
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    /*
     *  matrice.cpp
     *  Matrices
     *
     *  Created by Devouring Strossus on 06/05/09.
     *  Copyright 2009 __MyCompanyName__. All rights reserved.
     *
     */
     
    #include "matrice.h"
     
    using namespace std;
    /*
     **************************** initialisation **************************
     */
     
    //creer une matrice qui lit dans un fichier texte
    matrice::matrice()
    {
    	char chemin[200];
    	int cpt;
    	cout << endl << "chemin de la matrice : ";
    	cin >> chemin;
    	cout << endl;
    	ifstream fichier(chemin, ios::in);  // on ouvre le fichier en lecture
    	if(fichier)
    	{
    		// on lit le nombre de ligne et de colonne dans le fichier
    		fichier >> m_ligne;
    		fichier >> m_colonne;
     
    		// on déclare le tableau
    		m_tableau = new() double*[m_ligne];
    		for(cpt = 0 ; cpt < m_ligne ; cpt++)
    			m_tableau[cpt] = new() double[m_colonne];
    		// on lit les valeurs
    		int ligne, colonne;
    		for(ligne = 0 ; ligne < m_ligne ; ligne ++)
    		{
    			for(colonne = 0 ; colonne < m_colonne ; colonne++)
    			{
     
    				fichier >> m_tableau[ligne][colonne];
    			}
    		}
     
    	}
    	else
    		cerr << "Impossible d'ouvrir le fichier !" << endl;
     
    }
    // creer une matrice vide juste en donnant les lignes et colonnes
    matrice::matrice(int ligne, int colonne) : m_ligne(ligne), m_colonne(colonne)
    {
    	int cpt;
    	m_tableau = new() double*[m_ligne];
    	for(cpt = 0 ; cpt < m_ligne ; cpt++)
    		m_tableau[cpt] = new() double[m_colonne];
    	for(ligne = 0 ; ligne < m_ligne ; ligne ++)
    	{
    		for(colonne = 0 ; colonne < m_colonne ; colonne ++)
    		{
    			m_tableau[ligne][colonne] = 0.0;
    		}
    	}
    }
    // permet de copier une matrice à partir d'une autre
    matrice::matrice(const matrice &mat)
    {
    	int cpt;
    	m_ligne = mat.m_ligne;
    	m_colonne = mat.m_colonne;
    	m_tableau = new() double*[m_ligne];
    	for(cpt = 0 ; cpt < m_ligne ; cpt++)
    		m_tableau[cpt] = new() double[m_colonne];
    }
     
     
     
    // on entre les coordonnees a la main
    void matrice::initialisation()
    {	
    	int ligne, colonne;
    	for(ligne = 0 ; ligne < m_ligne ; ligne ++)
    	{
    		for(colonne = 0 ; colonne < m_colonne ; colonne++)
    		{
     
    			cout << endl << "Ligne : " << (ligne + 1) << " Colonne : "<< (colonne + 1)<<endl;
    			cin >> m_tableau[ligne][colonne];
    		}
    	}
     
    }
    /*
     ************************** AUTRE FONCTION *****************************
     */
    void matrice::affichage(ostream &out)
    {
    	int ligne, colonne;
    	for(ligne = 0 ; ligne < m_ligne ; ligne ++)
    	{
    		for(colonne = 0 ; colonne < m_colonne ; colonne++)
    		{
    			out << m_tableau[ligne][colonne]<< " ";
    		}
    		out << endl;
    	}
     
    }
     
     
    void matrice::translation(int Tx, int Ty, int Tz)
    {
    	int ligne , colonne, cpt;
     
    	matrice nouvelleMatrice(4,4), trans(4,4);
     
    	if(m_ligne == 4)
    	{
    		for(cpt = 0 ; cpt < 4 ; cpt++)
    			trans.m_tableau[cpt][cpt] = 1;
    		trans.m_tableau[0][3] = Tx;
    		trans.m_tableau[1][3] = Ty;
    		trans.m_tableau[2][3] = Tz;
     
    		nouvelleMatrice = trans * (*this);
     
     
    		for(ligne = 0 ; ligne < m_ligne ; ligne ++)
    		{
    			for(colonne = 0 ; colonne < m_colonne ; colonne ++)
    			{
    				m_tableau[ligne][colonne] = nouvelleMatrice.m_tableau[ligne][colonne];
    			}
    		}
     
    	}
    }
     
    void matrice::modificationProjection3D(matrice &mat, double plan)
    {
    	int ligne , colonne, cpt;
    	matrice nouvelleMatrice(4,4), trans(4,4);
     
    	for(ligne = 0 ; ligne < mat.m_ligne ; ligne ++)
    	{
    		for(colonne = 0 ; colonne < mat.m_colonne ; colonne ++)
    		{
    			nouvelleMatrice.m_tableau[ligne][colonne] = 0.0;
    		}
    	}
     
    	if(mat.m_ligne == 4)
    	{
    		for(cpt = 0 ; cpt < 3 ; cpt++)
    			trans.m_tableau[cpt][cpt] = 1.0;
    		trans.m_tableau[3][2] = 1 / plan;
     
    		cpt = 0;
    		for(ligne = 0 ; ligne < 4 ; ligne++)
    		{
    			for(colonne = 0 ; colonne < 4 ; colonne++)
    				cout << trans.m_tableau[ligne][colonne];
    			cout << endl;
    		}
     
    		nouvelleMatrice = mat * trans;
    	}
    	/*
    	if(nouvelleMatrice.m_tableau[0][3] != 1.0)// si les coordonnées homogénes ne sont pas égale à 1 on redivisie tout pas celleci
    	{
    		for(ligne = 0 ; ligne < nouvelleMatrice.m_ligne	; ligne ++)
    		{
    			for(colonne = 0 ; colonne < nouvelleMatrice.m_colonne ; colonne++)
    			{
    				nouvelleMatrice.m_tableau[ligne][colonne] /= nouvelleMatrice.m_tableau[3][0];
    			}
    		}
    	}*/
    	for(ligne = 0 ; ligne < m_ligne ; ligne ++)
    	{
    		for(colonne = 0 ; colonne < m_colonne ; colonne ++)
    		{
    			m_tableau[ligne][colonne] = nouvelleMatrice.m_tableau[ligne][colonne];
    		}
    	}
     
     
     
    }
     
    /*
     **********************  OPERATOR ***********************
     
     */
     
     
    matrice matrice::operator=(const matrice &mat)
    {
    	int ligne, colonne;
    	m_ligne = mat.m_ligne;
    	m_colonne = mat.m_colonne;
    	for(ligne = 0 ; ligne < m_ligne ; ligne++)
    	{
    		for(colonne = 0 ; colonne < m_colonne ; colonne++)
    		{
    			m_tableau[ligne][colonne] = mat.m_tableau[ligne][colonne];
     
    		}
     
    	}
    	return *this;
    }
    matrice matrice::operator+(const matrice &mat)
    {
    	int colonne, ligne;
    	matrice temp(m_ligne, m_colonne);
    	if(mat.m_colonne == m_colonne && mat.m_ligne == m_ligne)
    	{
     
     
    		for(ligne = 0 ; ligne < m_ligne ; ligne++)
    		{
    			for(colonne = 0 ; colonne < m_colonne ; colonne++)
    			{
    				temp.m_tableau[ligne][colonne] = mat.m_tableau[ligne][colonne] + m_tableau[ligne][colonne];
    			}
     
    		}
    	}
    	else
    		cerr << "impossible d'additionner les matrices"<< endl;
    	return temp;
    }
     
    matrice matrice::operator-(const matrice &mat)
    {
    	int colonne, ligne;
    	matrice temp(m_ligne, m_colonne);
    	if(mat.m_colonne == m_colonne && mat.m_ligne == m_ligne)
    	{
     
     
    		for(ligne = 0 ; ligne < m_ligne ; ligne++)
    		{
    			for(colonne = 0 ; colonne < m_colonne ; colonne++)
    			{
    				temp.m_tableau[ligne][colonne] = m_tableau[ligne][colonne] - mat.m_tableau[ligne][colonne];
    			}
     
    		}
    	}
    	else
    		cerr << "impossible d'additionner les matrices"<< endl;
    	return temp;
    }
     
    matrice matrice::operator*(const matrice &mat)
    {
    	int i, j, k;
    	matrice nouvellemat(m_ligne , mat.m_colonne);
     
    	//algo de multiplication de matrice qui marche
    	if(m_colonne == mat.m_ligne)
    	{
    		for (i = 0 ; i < m_ligne ; i++)
    		{
    			for (j = 0 ; j < mat.m_colonne ; j++)
    			{
    				for (k = 0 ; k < m_colonne ; k++)
    				{
    					nouvellemat.m_tableau[i][j] = m_tableau[i][k] * mat.m_tableau[k][j] + nouvellemat.m_tableau[i][j];
    				}
    			}
    		} 
    	}
     
    	else
    		cerr << "impossible de multiplier les matrices"<< endl;
    	return nouvellemat;
    }
     
    ostream &operator<<( ostream &out, matrice &mat)
    {
    	mat.affichage(out);
    	return out;
    }
     
     
     
     
    matrice::~matrice()
    {
    	int cpt;
    	for(cpt = 0 ; cpt < m_ligne ; cpt++)
    		delete[] m_tableau[cpt];
    	delete[] m_tableau;
    	m_tableau = NULL;
     
     
    }
    matrice.h
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    /*
     *  matrice.h
     *  Matrices
     *
     *  Created by Devouring Strossus on 06/05/09.
     *  Copyright 2009 __MyCompanyName__. All rights reserved.
     *
     */
    #ifndef DEFINEMATRICE
    #define DEFINEMATRICE
    #include <iostream>
    #include <string>
    #include <fstream>
    #include <cmath>
    #define LONGUEUR 20
    #define HAUTEUR 30
     
    class matrice 
    {
    public:
    	matrice();//avec fichier texte
    	matrice(int ligne, int colonne);//avec colonne et ligne
    	matrice(const matrice &mat);//copie
    	~matrice();
    	void initialisation();
    	void matrice::affichage(std::ostream &out);
    	void matrice::translation(int Tx, int Ty, int Tz);
    	void matrice::modificationProjection3D(matrice &mat, double plan);
    	matrice operator=(const matrice &mat);
    	matrice operator+(const matrice &mat);
    	matrice operator-(const matrice &mat);
    	matrice operator*(const matrice &mat);
     
     
     
    private:
    	int m_ligne;
    	int m_colonne;
    	double **m_tableau;
    };
    le main
    #endif
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        matrice test, test2, afiche(test);
    	cout << test << endl<< test2 << endl;
    	test = test * test2;
    	cout << test << endl;

    à mettre dans deux fichier texte
    matrice 1
    4 4
    16 15 14 13
    12 11 10 9
    8 7 6 5
    4 3 2 1
    matrice 2
    4 5
    1 2 3 4 1
    1 1 1 1 2
    1 1 1 1 1
    1 1 1 1 1


    le destructeur est très simple je desalloue les colonnes puis les lignes donc je pense pas que le problème vient de là j'ai l'impression que deux matrices pointe sur le même tableau

    voilà l'erreur que j'obtient
    16 15 14 13
    12 11 10 9
    8 7 6 5
    4 3 2 1

    1 2 3 4 1
    1 1 1 1 2
    1 1 1 1 1
    1 1 1 1 1

    58 74 90 106 42
    42 54 66 78 26
    26 34 42 50 10
    10 14 18 22 13

    Matrices(4147) malloc: *** error for object 0x402a0000: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    D'abord, si j'étais toi, j'éviterais l'utilisation de tableau de caractères (qui représentent des chaines C style, si le caractère qui suit le dernier caractère utile est un '\0') quand tu travailles en C++, même si tu utilise un tableau de taille fixe (tu l'auras sans doute deviné, je parle de ton "horrible" char chemin[200] )

    Je te conseillerais en effet très fortement de préférer l'utilisation de la classe string, disponible dans l'espace de noms std par simple inclusion du fichier d'en-tête <string>.

    Cette classe est expressément prévue pour gérer les chaines de caractères de manière bien plus sécurisée que tout ce que tu pourrais faire manuellement avec un char *

    En effet, si (j'espère juste ne pas devoir être l'opérateur qui devra l'introduire ), par le plus grand des malheurs, l'utilisateur vient à introduire un chemin qui contient plus de 199 caractères utiles, ton programme a de fortes chances de "partir en vrille" avant même d'avoir réellement pu commencer à travailler

    Tu trouvera une réponse à une bonne partie des questions que tu peux te poser sur la classe string directement sur la page de la fAQ qui lui est consacrée

    Un deuxième point qui me semble intéressant d'aborder avec toi, c'est la bonne délégation des tâches que tu dois impérativement essayer d'appliquer.

    En effet, s'il est effectivement du ressort du constructeur de ta classe matrice de l'initialiser correctement, il n'est absolument pas de son ressort de demander le nom du fichier qu'il doit utiliser, ni même, d'ailleurs, de gérer de lui-même le fichier qu'il devra lire.

    En effet, si, pour l'instant, tu décide de travailler en mode console, tu peux très bien envisager le fait que, d'ici deux semaines, tu décide de rajouter une interface graphique à ton application...

    L'affichage dans la console et la récupération du chemin du fichier à lire deviendront alors totalement inutiles, voire, dangereux pour ton application.

    De même, il n'est pas exclu que, trois jours après avoir décidé de passer sur une interface graphique, tu décides que, finalement, les données peuvent très bien venir d'ailleurs que d'un fichier présent sur le disque dur, et être, par exemple, transmises par le web.

    Tu devra alors toujours gérer un flux de données, mais ce ne sera plus un fichier en tant que tel.

    Et, à chaque fois, tu devra revoir ton constructeur parce qu'il ne correspond, décidément, pas aux besoins qu'il doit permettre de remplir.

    (Si tu estimes que je vais trop loin dans le futur de ton application, dis toi simplement que les besoins évoluent en permanence et que, même pour un exercice, il est bon d'en tenir compte )

    Ce qui est sympa pour nous, c'est que la plupart des flux d'entrée que tu pourra rencontrer sont, avant tout, ... des flux d'entrée, et qu'il existe une classe qui s'accommode parfaitement de travailler avec les flux d'entrée de toutes origines: la classe istream.

    C'est à dire que tu peux parfaitement "déléguer" la responsabilité de s'enquérir du nom du fichier à ouvrir et de l'ouvrir à une fonction particulière (hors du constructeur), ou à une autre d'ouvrir un port vers le serveur qui te fournira les entrée, de créer un flux de réception, et transmettre les deux au constructeur de manière tout à fait transparente pour le pour lui sous la forme... d'un flux d'entrée de base.

    (au passage, le 'I' de ifstream signifie, justement, qu'il s'agit d'un flux (stream) sur un fichier (le F) d'entrée (input)... il est donc inutile de préciser ios::in en second paramètre )

    A titre personnel, je serais même presque tenté de déléguer également la récupération du nombre de lignes et du nombre de colonnes à la fonction qui appelle le constructeur de ta classe matrice...

    De cette manière:
    • tu peux déjà au minimum envisager des vérifications sur la conformité des nombres obtenus, avant même d'appeler le constructeur de la matrice (et donc décider de ne pas le faire si les valeurs sont incohérentes)
    • tu peux décider d'utiliser les listes d'initialisations, ce qui te facilitera quand même énormément la tache

    Il reste un dernier (du moins, d'après ce que j'ai vu d'une lecture en diagonale de ton code) point important pour atteindre un niveau de fiabilité correct:

    Un constructeur ne devrait jamais gérer plus d'une allocation dynamique.

    En effet, une allocation dynamique de la mémoire a la mauvaise habitude de pouvoir... échouer qu'il s'agisse d'une allocation dynamique telle qu'on la pratique en C (avec malloc, realloc, etc) ou telle qu'on la pratique en C++ avec new.

    Et, le plus mauvais gout de cette manie est d'arriver... n'importe quand.

    C'est à dire que, si un jour, tu essaye d'allouer la mémoire pour une matrice de 10 000 lignes et de 10 000 colonnes, cela peut arriver tout aussi bien lorsque tu essaye d'allouer la mémoire pour contenir les 10 000 pointeurs sur les lignes que.. lorsque tu essaye d'allouer la mémoire pour contenir les 10 000 colonnes de la 9 999 eme ligne.

    Or, s'il échoue, l'opérateur new va lancer ce que l'on appelle une exception.

    Et le lancement de cette exception va avoir comme conséquence de rempnter l'ensemble de la pile d'appels jusqu'à arriver dans un (hypothétique) bloc try suivi d'un bloc catch capable de reconnaitre l'exception et de l'attraper.

    Ce qui est déjà sympa, c'est que l'ensemble des variables qui ne sont pas le fruit d'une allocation dynamique seront automatiquement détruites lorsque le lancement de l'exception fait que l'on quitte la portée dans laquelle elles sont déclarée, mais, pour ce qui est de la mémoire des variables pour lesquelles l'allocation dynamique a été utilisées, elle n'est pas libérée automatiquement, car le compilateur se souvient que... tu as décidé de prendre la responsabilité de gérer toi même le moment où cette mémoire est libérée.

    Évidemment, une fois que tu as perdu le pointeur correspondant, il te devient impossible de libérer la mémoire en question, ce qui provoque des "fuites mémoires" (memory leaks en anglais)

    Or, même si tu venais à décider de gérer ce risque directement au sein du constructeur, il devient difficile de gérer le moment précis où l'erreur survient:

    En effet, l'opérateur new lance l'exception std::bad_alloc s'il échoue à allouer la mémoire.

    Tu aurais donc un code proche de
    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
    Matrice::Matrice(std::ifstream& ifs, int l, int c):
             m_ligne(l),m_colonne(c)
    {
        try
        {
             m_tableau= new *double [l]; /* susceptible de lancer une
                                          *  std::bad_alloc (1)
                                          */
             for(int i=0;i<m_colonne;++i)
                 m_tableau[i]=new double [c]; /* susceptible de lancer une
                                              *  std::bad_alloc (2)
                                              */
        }
        catch(sdt::bad_alloc & e)
        {
            /* problème: est elle lancée en (1), et alors, il n'y a rien à faire
             * ou en (2) ???
             * et si elle est lancée en (2), c'est lorsque i (devenu inaccessible)
             * valait 1 ou... 9 999 ???
             */
        }
     
    }
    Pour résoudre ce problème, il existe plusieurs approches possibles:

    La première consiste à considérer qu'un tableau à deux dimensions de L lignes et de C colonnes peut parfaitement être considérer comme un tableau à une seule dimension de... L*C éléments.

    Pour accéder à l'élément se trouvant à la ligne l et à la colonne c, nous chercherions alors l'indice l*C+c.

    Cela te permettrait alors de n'avoir qu'à gérer un pointeur (et non plus un pointeur de pointeur) et de pouvoir te contenter d'un unique m_membre=new double[L*C]

    Mais cette pratique n'est valide que si tu as des matrices "pleines" et dont le nombre de colonnes est identique pour chaque ligne.

    La deuxième consiste à "déléguer les responsabilités".

    En effet, il existe un principe récurrent en programmation qui considère que si "quelque chose" (qu'il s'agisse d'une structure, d'une classe ou d'une fonction) a plus d'une responsabilité (on peut bien sur discuter sur la "granularité" du terme responsabilité ), c'est sans doute que ce quelque chose... a trop de responsabilités.

    L'idée est donc de déléguer la responsabilité de la gestion des colonnes au lignes de manière à ce que la matrice n'ait plus qu'à s'occuper... des lignes.

    Cela ne résoudra surement pas (pour l'instant) le problème d'avoir deux "new" dans le constructeur, mais cela te permettra de simplifier ta logique:

    En effet, la lecture de la matrice se limiterait à... appeler L fois la lecture de la ligne (cela n'a l'air de rien, mais tu gagne un niveau d'indentation dans ton code ) ce qui pourrait prendre la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Matrice::Matrice(std::ifstream& ifs, int l, int c):
             m_ligne(l),m_colonne(c)
    {
         /* j'ai omis le bloc try catch, car il n'apporte pas grand chose ici ;)
          * 
          * il est bien évident que m_tableau aura été transformé sous la forme
          * de ligne* m_tableau et que ligne est... la classe qui se charge 
          * de gérer les colonnes d'une ligne ;) 
          */
         m_tableau= new *ligne[l];
         for(int i=0;i<l;++i)
             m_tableau[i]= new ligne(ifs, m_colonne);
    }
    Enfin, il faut avouer que l'allocation dynamique de la mémoire (et surtout la libération de cette mémoire en temps opportun) est un véritable casse-tête, même pour les gens qui sont habitués

    Par chance, le C++ nous fournit de manière standard toute une série de classes qui s'en occupe parfaitement à notre place, et qui nous permettent de manipuler très facilement les différentes collections classiques que sont les tableaux de taille dynamique, les piles, les files, les listes et même les tableaux associatifs.

    Grâce à ces différentes classes, nous sommes en mesure de travailler avec les collections correspondantes sans (quasiment) jamais avoir recours à l'allocation dynamique, en étant sur que la libération de la mémoire se fera exactement quand il le faut.

    Pour la représentation de tableau, la classe qui nous intéresse, c'est la classe vector, disponible (comme tout ce qui est fournit par le standard) dans l'espace de noms std, par la simple inclusion du fichier d'en-tête <vector>

    C'est donc l'occasion de répéter une fois de plus un conseil qui apparait surement trois fois par semaine sur ce forum:
    il faut préférer les solutions propres au C++ (dans ce cas, la classe vector) à toute solution qui serait issue du C (dans ce cas, l'allocation dynamique d'un pointeur), car les solutions propre au C++ sont plus sécurisantes, plus simples à l'emploi, et rendent bien souvent le code beaucoup plus lisible.
    En effet, grâce à ces différentes classes, tu peux parfaitement en arriver à utiliser l'allocation dynamique de la mémoire que dans le cadre d'une mise en oeuvre du polymoprhisme, et encore, lorsqu'il est important que ta variable ait une durée de vie indépendante de l'objet ou de la fonction dans laquelle elle est créée.

    En outre, cela te simplifiera considérablement la vie car, grâce à l'abandon de l'allocation dynamique au profit de l'utilisation de la classe vector, tu pourra envisager de laisser le compilateur fournir l'implémentation par défaut pour le constructeur de copie, l'opérateur d'affectation et le destructeur, ce que tu ne peux pas faire lorsque tu décide de recourir à l'allocation dynamique de la mémoire.

    Au final, tu aurais donc quelque chose de fort proche de
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    class ligne
    {
        public:
            /* uniquement le constructeur, qui prend un flux d'entrées en 
             *paramètre, ainsi que le nombre de colonnes à créer
             */
            ligne(std::ifstream& ifs,  int col)
            {
                for(int i=0;i<col;++i)
                {
                    double d;
                    ifs>>d;
                    tab.push_back(d);
                }
            }
            /* les constructeur par copie, opérateur d'affectation et destructeurs
             * fournit par défaut par le compilateur nous conviennent parfaitement
             * 
             * d'autres fonctions peuvent être utiles par contre, comme le fait
             * de pouvoir accéder à l'élément qui se trouve à une colonne donnée
             */
        private:
            /* un tableau de double (chaque colonne étant représentée par un
             * double dans ton exemple)... qui connait en permanence sa taille :D
             */
            std::vector<double> tab; 
    };
    class matrice
    {
        public:
            matrice(std::ifstream ifs,  int l, int c)
            {
                /* nous nous contentons de demander l fois la lecture
                 * de la ligne et de placer la ligne lue dans le tableau
                 * correspondant
                 */
                for(int i=0;i<l)
                    tab.push_back(colonne(ifs,c));
            }
            /* même remarque que pour la classe ligne */
        private:
            std::vector<ligne> tab;
    };
    Bon, ce message ayant tout doucement tendance à se transformer en roman, je crois que je vais m' en arrêter là et te laisser le temps d'assimiler tout ce que j'ai pu écrire

    Je m'attarderai d'avantage sur ton code si tu décide de ne pas prendre ma prose en compte
    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
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    A lire le message d'erreur, j'aurais tendance à penser que ton problème se trouve dans le constructeur de copie ou l'opérateur d'affectation. En gros, tu crées une matrice temporaire, qui est à un moment désallouée par le destructeur, mais tu continue d'utiliser un pointeur ou une référence à celle ci.

    Un premier problème, c'est que ton constructeur de copie ne copie pas

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    matrice::matrice(const matrice &mat)
    {
    	int cpt;
    	m_ligne = mat.m_ligne;
    	m_colonne = mat.m_colonne;
    	m_tableau = new() double*[m_ligne];
    	for(cpt = 0 ; cpt < m_ligne ; cpt++)
    		m_tableau[cpt] = new() double[m_colonne];
    }
    Tu alloues bien tes lignes et tes colonnes, mais il te faudrait aussi recopier le contenu de mat. Ton code ne va probablement pas marcher, à cause de cela, mais je ne crois pas que ce soit cela qui cause ton bug...

    Ton opérateur d'affectation a un problème aussi

    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
    matrice matrice::operator=(const matrice &mat)
    {
    	int ligne, colonne;
    	m_ligne = mat.m_ligne;
    	m_colonne = mat.m_colonne;
    	for(ligne = 0 ; ligne < m_ligne ; ligne++)
    	{
    		for(colonne = 0 ; colonne < m_colonne ; colonne++)
    		{
    			m_tableau[ligne][colonne] = mat.m_tableau[ligne][colonne];
     
    		}
     
    	}
    	return *this;
    }
    D'abord, il ne vérifie pas une affectation du genre p=p, ensuite il peut, en théorie, changer le nombre des lignes et des colonnes, mais n'alloue pas la mémoire qu'il faut pour... Si tu fais cela, il va forcément se passer quelque chose d'horrible.

    Il y a peut être d'autres problèmes, mais ces deux là vont certainement empêcher ta classe de fonctionner... En les corrigeant, tu devrais déjà y voir plus clair.

    Et, comme le dit Koala01, mettre une fonction de lecture externe dans un constructeur par défaut n'est pas une bonne idée... Tu devrais définir soit une fonction de chargement, soit un constructeur spécialisé, qui prend le nom du fichier, ou un truc comme ca, en paramètre...

    Francois

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Janvier 2009
    Messages : 90
    Par défaut
    bon j'ai revu mon code pour le constructeur de copie et l'opérateur d'affection. Ca à l'air de beaucoup mieux marcher vu que je n'ai plus de message d'erreur.

    Concernant mon utilisation d'un tableau statique de char c'est du au fait que ifstream prend en paramètre un tableau de char et je ne savais pas qu'on pouvait qu'il existait une méthode pour convertir un string en char (c'est une bonne nouvelle d'ailleurs

    j'ai compris pourquoi il fallait éviter d'utiliser l'allocation dynamique mais pour ce projet que je dois finir pour bientôt je vais le laisser comme ça pour l'instant car il faut que je lise la doc et des tutos sur cette classe vector. En tout cas elle a l'air bien pratique.

    pour la délégation je vais modifier le constructeur principal de façon à qu'il ne gère que la création du tableau et qu'il mette les valeurs dedans.

    En tout cas merci à tout les deux j'ai appris plein de choses que je mettrais en pratique pour mes futurs projets

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 07/07/2007, 18h12
  2. Nombre double : écriture étrange
    Par ®om dans le forum Langage
    Réponses: 6
    Dernier message: 27/11/2006, 18h55
  3. Swing et double clique -> étrange pb
    Par adidmamah dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 13/09/2006, 09h09
  4. Problème étrange de précision avec double
    Par titoine1978 dans le forum DirectX
    Réponses: 4
    Dernier message: 22/02/2006, 09h26

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