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 de surcharge operateur '+' et '='


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut problème de surcharge operateur '+' et '='
    Salut à tous !
    je me remets (difficilement) au C++ après une 20aine d'années. je programme une classe 'matrice'. La surcharge de l'opérateur + ne fonctionne pas correctement. L'opération sur des matrices m, n et p du type
    p = m + n; renvoie une erreur : no matching function for call to 'matrice::matrice(matrice)' comme si le compilateur cherchait à appliquer le contructeur de copie au lieu de la fonction operator=.

    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
    // matrice.h
    #ifndef _Matrice_
    #define _Matrice_
    #include <iostream>
    using namespace std;
    class matrice{
        friend ostream& operator<<( ostream& flux, matrice &m);
        friend matrice operator+(const matrice &m1, const matrice &m2);
    public :
        matrice() { _li=0; _col=0; _val = 0;};
        matrice(int li, int col);
        matrice(matrice &m); // cons de copie
        float& operator()(int li, int col); // setter
        float operator()(int li, int col) const; // getter
        matrice& operator=(const matrice &m);
        int lignes(){ return _li;};
        int colonnes(){ return _col;};
    private :
        int _li, _col;
        float *_val;
    };
    #endif
     
    // matrice.cpp
    #include "matrice.h"
    matrice::matrice(int li , int col){
        _li = li;
        _col= col;
        _val = new float[_li * _col];
    }
    matrice::matrice(matrice &m){
        _li = m._li;
        _col = m._col;
        delete[] _val;
        int n = _li*_col;
        _val = new float[n];
        for(int i=0; i<n; i++)
            _val[i] = m._val[i];
    }
    matrice operator+(const matrice &m1, const matrice &m2){
        matrice temp(m1._li, m1._col);
        int n = temp._li * temp._col;
        for(int i = 0; i<n; i++)
            temp._val[i] = m1._val[i] + m2._val[i];
        return temp;
    }
    matrice &matrice::operator=(const matrice &m){
        if(this !=&m)
        {
            delete [] _val;
            _li = m._li;
            _col = m._col;
            int n = _li*_col;
            _val = new float[n];
            for(int i = 0; i<n; i++)
                _val[i] = m._val[i];
        }
        return *this;
    }
     
    //main.cpp :
    #include <iostream>
    #include "matrice.h"
    using namespace std;
    int main()
    {
        matrice m(3,3);
        for(int i = 0; i<3; i++)
            for(int j=0; j<3; j++)
                m(i,j) = i*3 + j;
        matrice n;
        matrice p;
        n = m;
        p = m + n; ! no matching function for call to 'matrice::matrice(matrice)'
                cout << p << endl;
        return 0;
    }

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    ce n'est pas la bonne façon de montrer du code.
    Ton constructeur par copie n'a pas une signature correcte.
    Tes getter devraient être const.

    Une déclaration du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Matrice p;
    p = m+n;
    a de fortes chances d'être optimisé par le compilateur pour faire appel au constructeur par copie depuis le résultat de l'opération au lieu de créer un p vide puis faire appel à l'opérateur d'affectation.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    je ne fais que tester la classe. je ne vois pas comment faire autrement que de déclarer la matrice avant de l'utiliser.
    D'accord pour la déclaration 'const' du constructeur de copie. Mais désolé, ça ne change rien au beugue !

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut ah le c.... !
    trouvé le beugue !
    Quel âne !

    Comme la fonction 'operator=' ressemble beaucoup au constructeur de copie, j'avais l'habitude de les programmer ensemble et de faire un copier coller. Là j'ai fait fort en recopiant l'instruction 'delete[] _val;' qui delete le pointeur avant sa création !
    voici le programme intégral corrigé et qui marche !
    Pour les grincheux, j'ai rajouté les 'const' manquants qui ne sont en rien responsable du beugue de ce programme !
    bon je sors !

    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
     
    // matrice.h
    #include <iostream>
    #include <iomanip>
    using namespace std;
     
    class matrice{
     
    	friend ostream& operator<<( ostream& flux, matrice &m);
    	friend matrice operator+(const matrice &m1, const matrice &m2);
     
     
    	public :
     
    	matrice()	{ _li=0; _col=0; _val = 0;};
    	matrice(int li, int col);
    	matrice(const matrice &m);		// cons de copie
    	~matrice(){_li=0; _col=0; delete[] _val; };
     
    	float& operator()(int li, int col);	// setter
    	float operator()(int li, int col) const;	// getter
    	matrice& operator=(const matrice &m);
     
    	int lignes(){ return _li;};
    	int colonnes(){ return _col;};
     
    	private :
    		int _li, _col;
    		float	*_val;
    };
     
     
    #endif
     
    // matrice.cpp
    /*
     *  matrice.cpp
     *  temp
     *
     *  Created by Pierre Tritsch on 20/05/13.
     *  Copyright 2013 -. All rights reserved.
     *
     */
     
    #include "matrice.h"
     
    matrice::matrice(int li , int col){
    	_li = li;
    	_col= col;
    	_val = new float[_li * _col];
    }
     
    matrice::matrice(const matrice &m){
    	_li = m._li;
    	_col = m._col;
    	int n = _li*_col;
    	_val = new float[n];
    	for(int  i=0; i<n; i++)
    		_val[i] = m._val[i];
    }
     
    ostream& operator<<( ostream& flux, matrice &m){
    	for(int i=0; i< m._li; i++)
    		for(int j = 0; j< m._col; j++)
    			{
    			if(j==0) flux << endl;
    			flux << setw(10) << m(i,j);
    			}
    	return flux;
    }
     
    float& matrice::operator()(int li, int col){
    	return(_val[li*_col + col]);
    }
     
    float matrice::operator()(int li, int col) const {
    	return(_val[li*_col + col]);
    }
     
    matrice operator+(const matrice &m1, const matrice &m2){
        matrice temp(m1);
    	int n = temp._li * temp._col;
        for(int i = 0; i<n; i++)
            temp._val[i] = temp._val[i] + m1._val[i];
        return temp;
        }
     
    matrice &matrice::operator=(const matrice &m){
        if(this !=&m)
            {
            delete [] _val;
            _li = m._li;
            _col = m._col;
            int n = _li*_col;
            _val = new float[n];
            for(int i = 0; i<n; i++)
                _val[i] = m._val[i];
            }
        return *this;
        }
     
    // main
    #include <iostream>
    #include "matrice.h"
     
    using namespace std;
     
    int main()
    {
        matrice m(3,3);
    	matrice n;
        matrice p(3,3);
        for(int i = 0; i<3; i++)
            for(int j=0; j<3; j++)
                m(i,j) = i*3 + j;
    	cout << "m : " << endl;
    	cout << m << endl;
     
        n = m;
        p = m + n;
     
     
    	cout << n << endl;
        cout << p << endl;
        return 0;
    }

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Pourquoi ne pas utiliser l'idiome Copy-and-Swap pour ton opérateur =?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    médinoc : parce que je ne connais pas !!!!!

    Comme noté en introduction je ne programme plus depuis 20 ans ! et je n'ai jamais entendu parler de ça. Si tu peux m'expliquer ?

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    OK, c'est assez simple: Tu commences par implémenter un Non-throwing swap dans ta classe, une fonction qui se contente d'échanger des valeurs entières, les pointeurs, et d'invoquer le non-throwing swap des objets contenus.
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <algorithm>
     
    void matrice::swap(matrice &obj)
    {
    	std::swap(_li, obj._li);
    	std::swap(_col, obj._col);
    	std::swap(_val, obj._val);
    }
    Ensuite, pour le Copy-and-swap, tu écris un opérateur = qui fait deux choses:
    • Une copie temporaire de l'objet source
    • Un swap entre l'objet actuel et la copie temporaire.

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    matrice& matrice::operator=(matrice tmp) //Passage par valeur: Ta copie temporaire est là
    {
    	tmp.swap(*this);
    }
    Le gros avantage, c'est que toute ta logique de copie est dans le constructeur de copie.

    PS: Évite les noms de variables membres commençant par un underscore, ça tend à être réservé à l'implémentation du langage. On tend à leur préférer les noms finissant par un underscore (ou dans l'école Microsoft, préfixés par "m_").
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    Médinoc,
    C'est effectivement génial de simplicité.
    ca bouffe pas trop de temps machine ?

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Normalement, pas plus que ce que tu dois faire normalement: Ce qui bouffe le plus, ce sont les new et delete (que tu dois faire de toute façon dans ton opérateur= ), aux côtés desquels permuter deux variables, c'est peanuts. En plus, std::swap est template, donc automatiquement inline (tant que personne je joue avec l’instanciation explicite de template, mais qui aurait intérêt à faire ça sur une fonction pareille?).

    Le gros avantage est l'exception-safety, vu qu'en théorie la seule chose qui puisse lancer des exceptions, c'est le constructeur de copie; et il est appelé avant toute tentative de modification de l'objet destination, donc en cas d'exception ni l'objet destination ni l'original de l'objet source ne sont affectés.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    Merci Médinoc !
    je vais regarder ça en détail ce soir.

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    PS: Au passage, peut-être devrais-tu implémenter un opérateur += (et possiblement, t'en servir dans l'implémentation de l'opérateur +).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    PS: Au passage, peut-être devrais-tu implémenter un opérateur += (et possiblement, t'en servir dans l'implémentation de l'opérateur +).
    En effet, la classe n'est pas terminée, manquent égalemant le caclul du déterminant, la multiplication scalaire , la multiplication matricielle et l'inversion.

  13. #13
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    Après test du "copy and swap", celui-ci s'avère un peu moins performant que la version classique de 'operator='.

    Une boucle de 10 000 itérations comportant une affectation de matrice type :
    n = m;
    donne comme temps de calcul :

    durée 0.001577 s pour la version swap
    durée 0.001333 s pour la version classique décrite plus haut.

    Pas quoi fouetter un chat mais la version classique est préférable si la vitesse est primordiale.

    Mais quelle facilité d'écriture et quelle tranquillité d'esprit avec le 'copy and swap' !

    Encore merci à Médinoc.

  14. #14
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Puisque tu t'y remets, je me permets de t'indiquer que ta manière d'écrire le code est peu courante en C++ moderne pour du vrai code (même si elle reste intéressante et utile pour l'apprentissage et la compréhension des mécanismes sous-jacents).

    L'idée est que plutôt de de gérer manuellement la mémoire utilisée par la classe, on peut déléguer cette partie à une classe qui le fait déjà, et on n'a plus alors qu'à ajouter les fonctionnalités qui nous intéressent, sans avoir à écrire les fonctions d'infrastructure, comme les constructeurs par copie. Ça fait très longtemps que dans du code de production je n'ai pas écrit de constructeur de copie ou d'operator=.

    Dans ton cas, on pourrait par exemple remplacer float *_val; par std::vector<float> _val;. Du coup, plus besoin de constructeur par copie, de destructeur, d'operator=, de swap, de constructeur par déplacement, d'operator= par déplacement (ces deux derniers sont des nouveautés du C++11). Le reste du code reste presque inchangé (appel du constructeur de vector plutôt que de new).
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  15. #15
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,
    Citation Envoyé par Peter57 Voir le message
    Après test du "copy and swap", celui-ci s'avère un peu moins performant que la version classique de 'operator='.

    Une boucle de 10 000 itérations comportant une affectation de matrice type :
    n = m;
    donne comme temps de calcul :

    durée 0.001577 s pour la version swap
    durée 0.001333 s pour la version classique décrite plus haut.
    Attend, tu nous parles de 0,244 milliseconde sur une boucle de 10 000 itérations, soit d'une différence d'à peu près 0,02 micro secondes par itération.

    Entre le manque de précision de la mesure et la différence éventuelle due à la charge du système au moment où le test a été effectué, on peut clairement considérer cet écart comme purement et simplement non significatif, du moins tant que tu ne nous donnera pas le code qui t'a permis de constater cet écart

    (Un principe de base est de ne jamais faire confiance en un benchmark que tu n'a pas trafiqué toi meme )
    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

  16. #16
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    je te donne le code ! tu pourras tester toi même !
    malgré des petites variations la différence reste toujours nette en défaveur du 'copy and swap'
    copy and swap :
    durée 0.154278
    durée 0.154406
    durée 0.153816
    durée 0.15542

    version classique :
    durée 0.124159
    durée 0.123874
    durée 0.124064
    durée 0.124143

    sur 1 000 000 de boucles. différence à peu près 20% !

    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
     
    // main
    #include <iostream>
    #include <ctime>
    #include "matrice.h"
     
    using namespace std;
     
    int main()
    {
        matrice m(3,3);
    	matrice n;
     
        for(int i = 0; i<3; i++)
            for(int j=0; j<3; j++)
                m(i,j) = i*3 + j;
     
    	clock_t	t;   
    	t = clock();            // initialisation T0
     
    	for (int i = 0; i<1000000; i++)
    		n = m;
     
    	t = clock()-t;         // t1 -t0 => nobre de clicks par seconde
     
    	float d = (float)t/CLOCKS_PER_SEC;  // nombre de secondes
     
    	cout <<"durée " << d << endl;
        return 0;
    }
     
    // matrice operator= avec swap
     
    void matrice::swap(matrice &m){
    	std::swap(_li, m._li);
    	std::swap(_col, m._col);
    	std::swap(_val, m._val);
    	}
     
    matrice& matrice::operator=(matrice m){	// version copy and swap
    	this->swap(m);
    	return *this;
    } // ne pas oublier de redéfinir déclaration dans matrice.h (enlever &)

  17. #17
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2007
    Messages : 57
    Points : 27
    Points
    27
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Puisque tu t'y remets, je me permets de t'indiquer que ta manière d'écrire le code est peu courante en C++ moderne pour du vrai code (même si elle reste intéressante et utile pour l'apprentissage et la compréhension des mécanismes sous-jacents).

    L'idée est que plutôt de de gérer manuellement la mémoire utilisée par la classe, on peut déléguer cette partie à une classe qui le fait déjà, et on n'a plus alors qu'à ajouter les fonctionnalités qui nous intéressent, sans avoir à écrire les fonctions d'infrastructure, comme les constructeurs par copie. Ça fait très longtemps que dans du code de production je n'ai pas écrit de constructeur de copie ou d'operator=.

    Dans ton cas, on pourrait par exemple remplacer float *_val; par std::vector<float> _val;. Du coup, plus besoin de constructeur par copie, de destructeur, d'operator=, de swap, de constructeur par déplacement, d'operator= par déplacement (ces deux derniers sont des nouveautés du C++11). Le reste du code reste presque inchangé (appel du constructeur de vector plutôt que de new).
    D'accord avec toi. Comme je l'ai dit plus haut je me remets au C++. J'ai été, je pense, un bon programmeur en C. Mais je n'ai jamais atteint le même niveau en C++, plus difficile à maitriser pour un amateur. Il y a trop de subtilités. Je cherche simplement à retrouver mes acquis et accessoirement à reconstituer ma bibliothèque de programme dont la classe 'matrice' faisait partie.
    Merci à toi

  18. #18
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Peter57 Voir le message
    je te donne le code ! tu pourras tester toi même !
    malgré des petites variations la différence reste toujours nette en défaveur du 'copy and swap'
    copy and swap :
    durée 0.154278
    durée 0.154406
    durée 0.153816
    durée 0.15542

    version classique :
    durée 0.124159
    durée 0.123874
    durée 0.124064
    durée 0.124143
    J'avoue être assez circonspect...

    J'ai fait un copié coller de ton code d'origine, et j'ai "juste" corrigé l'erreur de l'opérateur +.

    Comme je ne voulais pas forcément garder ce que j'ai fait pour un usage ultérieur, je me suis retrouvé avec un code ressemblant à
    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
    #include <iostream>
    #include <iomanip>
    #include <ctime>
    #include <algorithm>
    #include <vector>
    class matrice{
    public :
        matrice() { _li=0; _col=0; _val = 0;};
        matrice(int li, int col);
        matrice(const matrice &m); // cons de copie
        float& operator()(int li, int col); // setter
        float operator()(int li, int col) const; // getter
        matrice& operator=(const matrice &m);
        matrice operator+(const matrice & m2);
        int lignes(){ return _li;};
        int colonnes(){ return _col;};
    private :
        int _li, _col;
        float *_val;
    };
    class matricesc{
    public :
        matricesc() { _li=0; _col=0; _val = 0;};
        matricesc(int li, int col);
        matricesc(const matricesc & m); // cons de copie
        float& operator()(int li, int col); // setter
        float operator()(int li, int col) const; // getter
        matricesc& operator=( matricesc m);
        matricesc operator+(const matricesc & m2);
        int lignes(){ return _li;};
        int colonnes(){ return _col;};
    private :
        void swap(matricesc & other);
        int _li, _col;
        float *_val;
    };
    struct times{
    clock_t first;
    clock_t second;
    };
    int main(){
        std::cout<<CLOCKS_PER_SEC<<std::endl;
        std::vector <times> tab;
        for(int turn = 0;turn<10;++turn){
            times currentTime;
            {
     
            matrice m(3,3);
            matrice n;
     
            for(int i = 0; i<3; i++)
            for(int j=0; j<3; j++)
            m(i,j) = i*3 + j;
     
            clock_t	t;
            t = clock();            // initialisation T0
     
            for (int i = 0; i<1000000; i++)
            n = m;
     
            t = clock()-t;         // t1 -t0 => nobre de clicks par seconde
            currentTime.first = t;
            }
            {
     
            matricesc m(3,3);
            matricesc n;
     
            for(int i = 0; i<3; i++)
            for(int j=0; j<3; j++)
            m(i,j) = i*3 + j;
     
            clock_t	t;
            t = clock();            // initialisation T0
     
            for (int i = 0; i<1000000; i++)
            n = m;
     
            t = clock()-t;         // t1 -t0 => nobre de clicks par seconde
            currentTime.second = t;
     
     
            }
            tab.push_back(currentTime);
        }
        float somme = 0.0;
        for(size_t i = 0;i< tab.size(); ++i){
            clock_t first  = (float)tab[i].first;
            clock_t second = (float)tab[i].second;
            std::cout<<"exécution "<<i<<" : non swap = "<<first<<" swap = "<<second;
            float ratio;
            if(second < first){
            ratio = (float)first/(float)second;
            std::cout<<" swap plus rapide... ratio "<< ratio <<std::endl;
            }else{
            ratio = (float)second/(float)first;
            std::cout<<" non swap plus rapide... ratio "<< ratio <<std::endl;
            }
            somme += ratio;
        }
        float moyenne = somme/(float)tab.size();
        std::cout<<"ratio moyen "<<moyenne<<std::endl;
        return 0;
    }
    matrice::matrice(int li , int col){
        _li = li;
        _col= col;
        _val = new float[_li * _col];
    }
    matrice::matrice(const matrice &m){
        _li = m._li;
        _col = m._col;
        delete[] _val;
        int n = _li*_col;
        _val = new float[n];
        for(int i=0; i<n; i++)
            _val[i] = m._val[i];
    }
    matrice matrice::operator+(const matrice &m2){
        matrice temp(*this);
        int n = temp._li * temp._col;
        for(int i = 0; i<n; i++)
            temp._val[i] = _val[i] + m2._val[i];
        return temp;
    }
    matrice &matrice::operator=(const matrice &m){
        if(this !=&m)
        {
            delete [] _val;
            _li = m._li;
            _col = m._col;
            int n = _li*_col;
            _val = new float[n];
            for(int i = 0; i<n; i++)
                _val[i] = m._val[i];
        }
        return *this;
    }
    float& matrice::operator()(int l, int c){
    return _val[l*_col+c];
    }
    float matrice::operator()(int l, int c)const{
    return _val[l*_col+c];
    }
    matricesc::matricesc(int li , int col){
        _li = li;
        _col= col;
        _val = new float[_li * _col];
    }
    matricesc::matricesc(const matricesc &m){
        _li = m._li;
        _col = m._col;
        int n = _li*_col;
        _val = new float[n];
        for(int i=0; i<n; i++)
            _val[i] = m._val[i];
    }
    matricesc matricesc::operator+(const matricesc &m2){
        matricesc temp(*this);
        int n = temp._li * temp._col;
        for(int i = 0; i<n; i++)
            temp._val[i] = _val[i] + m2._val[i];
        return temp;
    }
    matricesc &matricesc::operator=( matricesc m){
       m.swap(*this);
        return *this;
    }
    void matricesc::swap(matricesc &m){
    	std::swap(_li, m._li);
    	std::swap(_col, m._col);
    	std::swap(_val, m._val);
    }
     
    float& matricesc::operator()(int l, int c){
    return _val[l*_col+c];
    }
    float matricesc::operator()(int l, int c)const{
    return _val[l*_col+c];
    }
    Même avec le code compilé en mode debug, sans optimisation, j'obtiens des résultats en faveur du swap and copy avec des valeurs de l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    exécution 0 : non swap = 0.666 swap = 0.147 swap plus rapide... ratio 4.53061
    exécution 1 : non swap = 0.271 swap = 0.147 swap plus rapide... ratio 1.84354
    exécution 2 : non swap = 0.276 swap = 0.149 swap plus rapide... ratio 1.85235
    exécution 3 : non swap = 0.272 swap = 0.146 swap plus rapide... ratio 1.86301
    exécution 4 : non swap = 0.276 swap = 0.149 swap plus rapide... ratio 1.85235
    exécution 5 : non swap = 0.284 swap = 0.146 swap plus rapide... ratio 1.94521
    exécution 6 : non swap = 0.276 swap = 0.147 swap plus rapide... ratio 1.87755
    exécution 7 : non swap = 0.285 swap = 0.15 swap plus rapide... ratio 1.9
    exécution 8 : non swap = 0.284 swap = 0.149 swap plus rapide... ratio 1.90604
    exécution 9 : non swap = 0.283 swap = 0.15 swap plus rapide... ratio 1.88667
    et, compilé en mode release, j'obtiens toujours un avantage pour la version swap and copy, d'ailleurs un légèrement plus marqué, avec des valeurs de l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    exécution 0 : non swap = 0.652 swap = 0.084 swap plus rapide... ratio 7.76191
    exécution 1 : non swap = 0.203 swap = 0.085 swap plus rapide... ratio 2.38824
    exécution 2 : non swap = 0.209 swap = 0.083 swap plus rapide... ratio 2.51807
    exécution 3 : non swap = 0.205 swap = 0.084 swap plus rapide... ratio 2.44048
    exécution 4 : non swap = 0.207 swap = 0.084 swap plus rapide... ratio 2.46429
    exécution 5 : non swap = 0.212 swap = 0.084 swap plus rapide... ratio 2.52381
    exécution 6 : non swap = 0.203 swap = 0.089 swap plus rapide... ratio 2.2809
    exécution 7 : non swap = 0.212 swap = 0.091 swap plus rapide... ratio 2.32967
    exécution 8 : non swap = 0.214 swap = 0.085 swap plus rapide... ratio 2.51765
    exécution 9 : non swap = 0.209 swap = 0.084 swap plus rapide... ratio 2.4881
    avais tu pensé à faire tes tests en mode release (visual studio est connu pour faire beaucoup de choses en plus en mode débug )
    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

  19. #19
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Attention, tu as introduit un savré biais dans ton code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    matrice &matrice::operator=(matrice m)
    devrais être

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    matrice &matrice::operator=(const matrice& m)

  20. #20
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Je ne vois pas trop quelle différence supprimer la forme optimisée du copy-and-swap causerait ici, je ne vois pas d'endroit où on utilise l'opérateur = avec un temporaire...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. Problème de surcharge d'operateur
    Par CodeurNé dans le forum C++
    Réponses: 2
    Dernier message: 29/12/2012, 18h51
  2. Problème de surcharge d'operateur <
    Par Shuret dans le forum C++Builder
    Réponses: 6
    Dernier message: 11/04/2008, 18h16
  3. Petit probléme de surcharge d'opérateur .
    Par Clad3 dans le forum C++
    Réponses: 20
    Dernier message: 11/04/2005, 20h15
  4. Problème de surcharge d'opérateurs
    Par Hell dans le forum C++
    Réponses: 17
    Dernier message: 17/01/2005, 16h01
  5. Réponses: 2
    Dernier message: 25/07/2004, 23h24

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