Operator et pointeur [C++] [Résolu/Fermé]

Signaler
Messages postés
9713
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
13 septembre 2019
-
 Benur29 -
Bonjour, je fait une classe Matrix, defini comme ça :
struct Matrix{vector<double>M;}
pour définir l'opérateur multiplier :
Matrix& operator*(matrix& A, Matrix& B)
{matrix *tmp;
tmp=new matrix;
// calculs du produit que je vous épargne
return *tmp;}
voila l'algorithme de base. Le programme parfaitement, mise à par une ENORME fuite de mémoire qui est du au fait que tmp ne soit pas détruit à la fin de l'apel de la fonction.
Je ferai bien la declaration de tmp en non-pointeur, mais le compilateur me dit que je retourne un variable local. Et si j'enleve les "&" , le compilateur n'est pas content non plus, ou alors le programme plante pour violation d'acces.
Je sais que le problème n'est pas facile, mais la je seche...
Si quelqu'un pouvait m'aider, je lui en serai très reconnaisant.
Merci

Salutation !
Char Snipeur

9 réponses

Messages postés
488
Date d'inscription
vendredi 16 avril 2004
Statut
Membre
Dernière intervention
15 mars 2009
156
dans le constructeur de matrix, tu peux mettre un new, il y a même
moyen( de passer un paramètre pour la taille d'allocation lors de la déclaration d'une instance de matrix.
matrix(1) *a; avec un new dedans. (1 à multiplier par sizeof de matrix dans le constructeur)
et dans le destructeur le delete[]
Les constructeurs par défaut servent surtout à ça.

autrement, je sais qu'il n'est pas interdit de faire de l'allocation statique:
Matrix& operator*(matrix A[2], Matrix B[2] );
le compilateur se débrouille tout seul pour l'allocation.
Je sais pas si c'est la solution, mais il y a sûrement encore d'autres moyens.

a+
Messages postés
9713
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
13 septembre 2019
1 138
Merci de ta réponse blurk. Je n'ai pas tout compris surtout car j'ai toujours essayer d'éviter les new et delete. Je ne sais pas très bien comment ils fonctionnent... Je vais me renseigner.
en fait pour l'opérateur, les "&" dans l'apel, si je ne les met pas, j'ai des erreurs de calcul : le passage par valeur se fait rès mal. En plus il me parait un peu restrictif de donnée une taille de matrice dans l'appel "matrix A[2]" si je fait une matrice plus grande, je fait comment?

Salutation !
Char Snipeur
Matrix& operator*(matrix& A, Matrix& B)

l'opérateur * doit retourner *this et pas un objet temporaire alloué !

oups désolé je viens de dire une grosse BETISE.
c'est la fatigue.
j'arretes de bosser, je rentre chez moi et je corrige ce code demain ...

Je reviens après 10 cafés, ça va mieux

Conventions classiques C++
- l'opérateur * rend Matrice
- l'opérateur *= rend une Matrice*
-ils prennent tous les 2 un seul paramètre

donc
Matrice& operator*=(matrix& b)
{
return *this = *this * b; // ici il FAUT que l'opérateur = existe ET on se sert de l'opérateur * écrit ci dessous
}

Matrice operator*(matrix& b) {
Matrice c(this->getNbLigs(), this->getNbCols());
//remplissage de c
return c; // ici il FAUT que le constrcuteur de copie existe
}

tu dois définir aussi

Matrice& operator=(matrix& b) { // opérateur d'affetatiion
// ...
}

Matrice(matrix& b) { // constrcuteru de copie
// ...
}


est-ce clair ?

marvinrouge
Bien que la discussion soit terminée depuis belle lurette, je la complète pour éclairer d'autres esprits

si on déclare ainsi alors on doit retourner *this :
Matrice& operator*=(matrix& b)
{
return *this = *this * b; // ici il FAUT que l'opérateur = existe ET on se sert de l'opérateur * écrit ci dessous
}


par contre si on déclare de la façon qui suit, on peut retourner une valeur construite dans la fonction membre :
Matrice& operator*=(matrix& b) const
{
Matrice* resultat = new Matrice(param_d-init-du_constructeur);
.....
return *resultat
}

En espérant vous éclairer
Messages postés
9713
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
13 septembre 2019
1 138
Salut.
Après des tests, et vue que j'ai apris un peu mieux le C++.
Le mieux est d'utiliser :
Matrix operator*(Matrix& A, Matrix& B);
cette fonction est défini en dehors de la class, c'est une surcharge de l'opérateur binaire '*'
J'ai enlever le '&' dans le retour de la fonction, car c'est la valeur qui nous intéresse, il n'y a aucune utilité de modifier A*B (A*B=6 n'a pas de sens en affectation) J'ai mis des '&' dans les paramètres de la fonctions pour passer les références des objets, car cela évite les erreurs de recopie et gagne du temps de recopiage des objets.
daccord sur la fonction membre 'operator*=' elle est parfaite.
en revanche la fonction 'matrix& operator*(matrix& b)' génère toujours des fuites de mémoire car la matrice resultat n'est jamais détruite. Dans ce cas, il est possible (3 matrice A,B et C) de faire :
A*B=C, resultat prend la valeur de C par l'opérateur '=' mais A et B ne sont pas modifier. et à chaque fois que tu fera A*B tu créra une nouvelle variable resultat .
la solution :

matrix& operator*(matrix& b)const
{
matrix* result = new matrix(.......);

...........

return = *result;
}

mais bon fais comme tu le sens hein ..........lol

bon amusement
Messages postés
9713
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
13 septembre 2019
1 138
Je maintient, ta solution n'es pas bonne car elle engendre une fuite de mémoire, et aussi pour les raisons exposés dans le messsage précédent.
Messages postés
29238
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
27 mars 2020
6 812
Tout à fait d'accord avec charsniper mais en fait c'est presque bon :
matrix operator*(matrix& b)const {
  matrix result(.......); 
   //...
  return result
}

En fait si tu calcule A*B tu es effectivement de créer une matrice C=A*B et donc de l'allouer (car tu ne veux modifier ni A, ni B). Cependant qui dit new dit delete, et ici le delete n'était jamais fait (donc la mémoire occupée par C jamais rendue).

Ici tu ne peux pas retourner une référence, ça n'a pas de sens. Retourner une référence n'a de sens que si c'est une variable qui est déjà créée. Typiquement quand tu passes une variable en paramètre, on passe en générale la référence car ça évite de recopier dans la pile la variable passée en paramètre. Ici tu es de toutes façons condamné à créer une nouvelle variable de retour C donc... on la retourne directement :)

Au niveau allocation c'est mieux, car la variable de retour sera déclarée sans new et sera donc automatiquement détruite à la fin du scope ou elle est déclarée :
matrix A,B;
//Initialisation de A et B
//...

// Calcul de C = A*B
{
  int x=69;
  matrix C = A*B;
   //...
} // C est détruite en arrivant à cette accolade au même titre que x

Bonne chance
ok ; autant pour moi

En ce ki concerne tes fuites memoire : je suppose que tu utilises des tableaux intermédiaires.

si tu les alloues dynamiquement : n'oublie pas de les détruire proprement :

int* tab = new int[n];
....
delete[] tab;


int** tab = new int*[n1]; //tab[n1][n2]
for(int j= 0; j<n1 ; j++)
{
tab[j] = new int[n2];
for(int h=0; h<n2 ; h++)
{
tab[j][h] = .........;
}
}
......
for(j= 0; j<n1 ; j++)
{
delete[] tab[j];
}

delete[] tab;

avec ça c propre