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 :

Surcharge d'opérateurs et affectation


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de Nadd
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    160
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 160
    Par défaut Surcharge d'opérateurs et affectation
    Bonsoir,

    J'ai crée une classe t_matrix dont certains opérateurs ont été surchargés, afin notamment de supporter l'addition, la soustration et la multiplication de deux objets t_matrix. Les données sont stockées dans un tableau float *. Voici les prototypes de ces surcharges :

    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
     
            // operator=:
            //  defines operator =
            t_matrix & operator=(const t_matrix & toCopy);
     
            // operator+:
            //  computes this+arg
            t_matrix operator+(const t_matrix & arg);
     
            // operator-:
            //  computes this-arg
            t_matrix operator-(const t_matrix & arg);
     
            // operator*:
            //  computes this*arg
            t_matrix operator*(const t_matrix & arg);
     
            // operator*:
            //  computes this*arg
            t_matrix operator*(const double arg);
     
            // operator*:
            //  computes arg*_matrix
            friend t_matrix operator*(const double arg, const t_matrix & _matrix);
    J'ai également défini un constructeur de copie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
            // t_matrix:
            //  constructor of copy
            t_matrix(const t_matrix & toCopy);
    Prenons un exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    t_matrix A(3, 3, 1.0); // dim : m*n, valeur initiale = 1.0
    t_matrix x(3, 3, 3.0);
    t_matrix K = A*x;
    t_matrix L = A;
    t_matrix M(3, 3, 0.0);
    M = A;
    Lorsque j'effectue l'affectation via t_matrix L = A, le constructeur de copie est bien appelé et fait son travail. Lorsque j'effectue l'affection via M = A, il s'agit de l'opérateur d'affectation. Mais lorsque j'effectue A*x, qui retourne un objet de type t_matrix, ni le constructeur de copie ni l'opérateur d'affectation n'est appelé.

    J'obtiens donc par la suite des erreurs de double free or corruption probablement à cause d'un double appel delete mat, où mat est de type float *.

    Une subtilité (ou pas) doit probablement m'échapper... Help!

    En vous remerciant d'avance,

    Nicolas.

  2. #2
    Membre confirmé Avatar de Nadd
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    160
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 160
    Par défaut
    Après recompilation, le tout semble fonctionner.

    Le constructeur de copie est bien appelé pour t_matrix L = A*x.

    EDIT:

    Le fait d'utiliser t_matrix & t_matrix(const t_matrix & toCopy) ou t_matrix t_matrix(const t_matrix & toCopy) semble affecter le fonctionnement du problème : l'opérateur d'affectation est appelé dans tous les cas lorsque le retour s'effectue par référence alors que le constructeur de copie et l'opérateur d'affectation sont appelés tous les deux (reste à savoir dans quels cas) lorsqu'il n'y a pas de &.

    Pourquoi ?

  3. #3
    Membre éprouvé Avatar de Xtrem_Voyageur
    Homme Profil pro
    Inscrit en
    Juin 2009
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2009
    Messages : 85
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Le fait d'utiliser t_matrix & t_matrix(const t_matrix & toCopy) ou t_matrix t_matrix(const t_matrix & toCopy)
    Je suppose qu'il s'agit d'une maladresse mais un contructeur ne retourne rien.

    Quand tu fais
    Effectivement, la matrice L est déclarée et initialisée pour la première fois, c'est donc bien le constructeur par copie qui est appelé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    t_matrix(const t_matrix& toCopy)
    Il se charge de construire et initialiser ta matrice L à partir d'un référence sur la matrice 'TEMP' retournée par A*x.

    Quel est ton problème, qu'est ce qui ne fonctionne pas?

  4. #4
    Membre confirmé Avatar de Nadd
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    160
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 160
    Par défaut
    Bonjour,

    Je suppose qu'il s'agit d'une maladresse mais un contructeur ne retourne rien.
    Effectivement. Heureusement, elle ne figure pas dans mon code.

    Selon que j'utilise cette définition :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    t_matrix operator=(const t_matrix & arg)
    ou celle-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    t_matrix & operator=(const t_matrix & arg)
    pour l'opérateur d'affectation, le comportement du programme n'est pas le même. Lorsque la première définition est utilisée, l'opérateur d'affectation et le constructeur de copie sont tous les deux utilisés durant le programme (il s'agit d'un algorithme de point intérieur). Lorsque la seconde définition est utilisée, seul l'opérateur d'affectation est utilisé. Or, le résultat retourné par le programme est identique (et correct) dans les deux cas.

    Je cherche donc à comprendre pourquoi...

    Bien à vous,

    Nicolas.

  5. #5
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    l'operator= renvoie *par définition* une reference vers l'objet modifié.
    Si tu renvois une valeur, tu va la copier a chaque sortie de =.

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,

    Citation Envoyé par Nadd Voir le message
    Une subtilité (ou pas) doit probablement m'échapper... Help!
    Une erreur dans le constructeur de copie, l'opérateur d'affectation ou l'opérateur surchargé. En l'absence de leur code, difficile de répondre.

    Ensuite, tu peux séparer la gestion du stockage de la classe matrice (SRP quand tu nous tiens). Cela clarifiera les différentes classes ne leur laissant qu'une seule responsabilité bien identifiée.

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Ensuite, tu peux séparer la gestion du stockage de la classe matrice (SRP quand tu nous tiens). Cela clarifiera les différentes classes ne leur laissant qu'une seule responsabilité bien identifiée.
    C'est ce que j'ai fait avec la mienne, mais du coup, je me demande quelle est la responsabilité de ma classe Matrix, complètement dépouillée... Il n'y reste que des opérateurs, en gros.
    D'ailleurs, un commentaire sur le site d'Emmanuel Deloget fait mention d'un pattern "anémique". :-)

  8. #8
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Citation Envoyé par oodini Voir le message
    C'est ce que j'ai fait avec la mienne, mais du coup, je me demande quelle est la responsabilité de ma classe Matrix, complètement dépouillée... Il n'y reste que des opérateurs, en gros.
    D'ailleurs, un commentaire sur le site d'Emmanuel Deloget fait mention d'un pattern "anémique". :-)
    Responsabilité d'une classe matrice ? Offrir la sémantique nécessaire pour représenter le concept mathématique d'une matrice (et rien d'autre) (*). C'est la première idée qui me vient et me semble suffisament fine (**), on remarque d'ailleurs qu'elle n'inclut aucune idée sur le stockage (par exemple).

    (*) Par extension ca s'applique à n'importe quel élément des mathématiques qu'on voudrait introduire dans un architecture logiciel.

    (**) Elle peut demander d'être préciser. Le concept mathématique de matrice est lié à suffisament d'autre concepts pour (au moins) se poser des questions (application linéaire sur un espace vectoriel par exemple). Ca peut aussi dépendre de ce qu'on va en faire et de la granularité qu'on désire.

  9. #9
    Membre confirmé Avatar de Nadd
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    160
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 160
    Par défaut
    Bonsoir,

    Voici le code du constructeur de copie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        t_matrix::t_matrix(const t_matrix & toCopy) : m(toCopy.m), n(toCopy.n)
        {
            mat = new double[m*n];   
            cblas_dcopy(m*n, toCopy.mat, 1, mat, 1);
        }
    et celui de l'opérateur d'affectation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
        t_matrix & t_matrix::operator=(const t_matrix & toCopy)
        {
            m = toCopy.m, n = toCopy.n;
     
            mat = new double[m*n];
            cblas_dcopy(m*n, toCopy.mat, 1, mat, 1);
     
            return *this;
        }
    Sous cette version, l'opérateur d'affection est le seul a être appelé, même pour ce genre d'instruction : t_matrix y = A*x.

    Les données de la matrice sont stockées dans une variable double * afin de s'aligner sur les spécifications de CBLAS.

    N'ayez crainte, l'absence de vérifications sur les paramètres est volontaire.

    Le principe de responsabilité unique est intéressant. Néanmoins, je ne pense pas en avoir l'utilité pour le moment.

    Bien à vous,

    Nicolas.

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Citation Envoyé par Nadd Voir le message
    Le principe de responsabilité unique est intéressant. Néanmoins, je ne pense pas en avoir l'utilité pour le moment.
    Très drôle ! Un principe de base de l'architecture logicielle ? Ne pas en avoir besoin. Cela revient à dire : "je pourrais bien coder, mais je n'en ai pas besoin. Alors je pense que je vais faire que du code spaghetti." Sérieusement, c'est très drôle. Évite de dire ça à ton client quand même.

    L'opérateur = provoque une fuite mémoire.

    Cf l'idiom copy&swap

    Pourquoi ne pas utiliser un std::vector<double> ?

    A quoi ressemblent :
    => le constructeur par défaut,
    => le destructeur,
    => l'opérateur *
    ?

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

Discussions similaires

  1. Surcharge de l'opérateur d'affectation
    Par PoZZyX dans le forum Windows Forms
    Réponses: 6
    Dernier message: 23/07/2012, 15h30
  2. Surcharge de l'opérateur d'affectation
    Par Zangdaarr dans le forum Langage
    Réponses: 9
    Dernier message: 29/03/2011, 22h00
  3. Surcharge de l'opérateur d'affection
    Par ProgVal dans le forum C++
    Réponses: 4
    Dernier message: 06/04/2008, 16h45
  4. Réponses: 2
    Dernier message: 11/01/2008, 10h40
  5. [VB .NET] Surcharge d'opérateur
    Par Franckintosh dans le forum VB.NET
    Réponses: 2
    Dernier message: 07/09/2004, 19h05

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