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

Langage C++ Discussion :

surcharge d'opérateur optimisée


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Par défaut surcharge d'opérateur optimisée
    Bonjour,

    Il y a une question qui me turlupine :

    Si je surcharge une méthode-opérateur (par exemple operator+) il est bien évident qu'il est préférable de faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A operator+(const A&) const;
    Plutôt que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A operator+(const A) const;
    Surtout si la copie de A est chère ... (on communique 4 octets à la place de la taille de A)

    En revanche, une fois que la méthode renvoie l'objet A et que je l'affecte ou que je l'utilise dans mon code appelant (forcément sinon ça n'a pas d'intérêt ^^), y a-t-il à ce moment une copie ou bien est-ce fait de manière intelligente ?

    J'imagine qu'il y a une copie non ?

    Si il y a une copie, comment contourner ce problème ?

    Si cela n'est pas possible, il serait plus judicieux de faire quelque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A* operator+(const A*,const A*);
    Donc en faisant une fonction externe, en manipulant uniquement des pointeurs, en faisant un "new" dans la fonction, et lors du retour, l'affectation ne va transférer que 4 octets.

    Le problème avec ça c'est que l'appelant va devoir se charger du delete.

    Qu'en pensez-vous ?

    Je vous remercie par avance pour vos avis éclairés !

  2. #2
    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
    En général l'opérateur + se code comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    A operator+(const A& lhs, const A& rhs)
    { A result = lhs; result += rhs; return result; }
    Et il n'y a pas de copie en retour si le compilateur fait son boulot, c'est le NRVO (cf FaQ).

  3. #3
    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 : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    En général l'opérateur + se code comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    A operator+(const A& lhs, const A& rhs)
    { A result = lhs; result += rhs; return result; }
    Et il n'y a pas de copie en retour si le compilateur fait son boulot, c'est le NRVO (cf FaQ).
    Voire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    A operator+(A lhs, const A& rhs)
    { lhs += rhs; return lhs; }
    Vu que de toute manière il faut bien faire la copie et ainsi tu laisse la possibilité au compilo d'optimiser cette copie (j'avais vu passer un article intéressant à ce sujet mais je n'arrive plus à remettre la main dessus).

  4. #4
    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
    @gl: Non, si tu fais ca tu gagnes la copy-elision pour certains cas mais tu perds le NRVO à chaque fois (il y a des condition pour que le NRVO soit possible, et ca marche pas sur les paramètres). On devrait faire ca pour l'opérateur d'affectation par contre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    A& operator=(A rhs)
    { swap(rhs); return *this; }
    Tu as peut-etre vue ca dans un des articles de la série sur la move semantic de cpp-next, pour être exact c'est ca qu'il conseil de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    A operator+(A lhs, const A& rhs)
    {
      lhs += rhs;
      A result;
      swap(result,lhs);
      return result;
    }
    D'après l'auteur (et d'après mes souvenirs de l'article ...), c'est sensé activer à la fois le NRVO et la copy-elision, et donc sur quelque-chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A foo(){return A();}
    A a;
    A b = foo() + a; //1
    On ne devrait pas avoir de copie à la ligne 1 (le NRVO fait qu'il n'y a pas de copie au retour, et la copy-elision pas de copie au passage) le biais, ce que quand j'avais testé, il y avait quand même des copie du au swap, alors que d'après l'auteur un compilateur intelligent aurait du optimiser ce passage.

    Et ensuite il présente un autre problème, qui fait que dans certains cas on se retrouve avec encore plus de copie qu'avec la première méthode (et ensuite il introduit la solution avec la move-semantic, cf l'article).

  5. #5
    Membre confirmé

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Par défaut
    Déjà, merci pour vos réponses.

    J'ai lu vos réponses mais il va falloir que je regarde ça demain à nouveau, le problème semble plus épineux que je ne le pensais ...

    Peut-être faut-il éviter les surcharges d'opérateurs classiques et passer par des pointeurs (avec un new dans la méthode et renvoyer le pointeur) comme ça on n'est sur que les données ne sont brassées qu'une fois et qu'ensuite seule l'adresse est renvoyée. Ca demande juste de faire attention aux fuites de mémoire.

    Je regarderai ça après une nuit de repos

  6. #6
    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
    Citation Envoyé par Michel_57 Voir le message
    Peut-être faut-il éviter les surcharges d'opérateurs classiques et passer par des pointeurs (avec un new dans la méthode et renvoyer le pointeur) comme ça on n'est sur que les données ne sont brassées qu'une fois et qu'ensuite seule l'adresse est renvoyée. Ca demande juste de faire attention aux fuites de mémoire.
    )
    Non jamais. Deja operator+(A*,A*), je pense que ca ne marche meme pas vu que T* est un type de base qqsoit T.

    Passe des references, fait de la NRVO et du swap et hop.

  7. #7
    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 : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Tu as peut-etre vue ca dans un des articles de la série sur la move semantic de cpp-next, pour être exact c'est ca qu'il conseil de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    A operator+(A lhs, const A& rhs)
    {
      lhs += rhs;
      A result;
      swap(result,lhs);
      return result;
    }
    D'après l'auteur (et d'après mes souvenirs de l'article ...), c'est sensé activer à la fois le NRVO et la copy-elision, et donc sur quelque-chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    A foo(){return A();}
    A a;
    A b = foo() + a; //1
    On ne devrait pas avoir de copie à la ligne 1 (le NRVO fait qu'il n'y a pas de copie au retour, et la copy-elision pas de copie au passage)
    Certes, j'ai légèrement zappé un bout dans ma réponse, au temps pour moi.

    Citation Envoyé par Flob90 Voir le message
    le biais, ce que quand j'avais testé, il y avait quand même des copie du au swap, alors que d'après l'auteur un compilateur intelligent aurait du optimiser ce passage.
    Ca c'est le vrai problème de tout ce qui concerne "la qualité de l'implémentation", il n'y a pas nécessairement le même gain en fonction du compilateur utilisé (parfois aucun gain du tout voire une dégradation).

    Pour ma culture personnelle, avec quel compilateur avais-tu testé ?

    Citation Envoyé par Flob90 Voir le message
    Et ensuite il présente un autre problème, qui fait que dans certains cas on se retrouve avec encore plus de copie qu'avec la première méthode (et ensuite il introduit la solution avec la move-semantic, cf l'article).
    Effectivement, le move-semantic résous pas mal de souci.


    PS : aurais-tu par hasard encore le pointeur sur l'article car je ne le retrouve plus (je crois que j'ai atteins les limites de mon système de non-classement par strate).

  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
    (J'avais testé sous Windows Vista avec gcc4.5.1 proposé par TDM. Faudra que je fasse d'autre tests).

    L'article auquel je pense c'est celui-ci : http://cpp-next.com/archive/2009/09/...our-next-move/

    @Michel_57: Il y a quelques subtilités, mais non il ne faut pas faire d'allocation dynamique et de pointeurs, à par complexifier la chose tu ne gagneras pas grand chose. Si tu veux faire des tests, prends cette classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    struct A
    {
      A(){ std::cout << " ctor "; }
      A(const A&){ std::cout << " copy-ctor "; }
      A& operator=(A){ std::cout << " assigation "; return *this; }
      A& operator+=(const A&){ return *this; }
    };
    Et essaies d'écrire des opérateurs + et testes les dans le main, tu verras sur la sortie le nombre de copie/construction/affectation, et tu verras que tu feras surment pas beaucoup mieux que la forme canonique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    A operator+(const A& lhs, const A& rhs)
    { A result = lhs; result += rhs; return result; }
    Ou que si tu fais mieux ca sera au prix d'un système complexe qui pourrait dérouter l'utilisateur.

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

Discussions similaires

  1. [C#] Tri d'objet et surcharge d'opérateur
    Par Royd938 dans le forum Windows Forms
    Réponses: 6
    Dernier message: 17/12/2007, 00h26
  2. Petit probléme de surcharge d'opérateur .
    Par Clad3 dans le forum C++
    Réponses: 20
    Dernier message: 11/04/2005, 20h15
  3. Problème de surcharge d'opérateurs
    Par Hell dans le forum C++
    Réponses: 17
    Dernier message: 17/01/2005, 16h01
  4. Cumul de surcharges d'opérateurs
    Par Nats dans le forum C++
    Réponses: 2
    Dernier message: 11/10/2004, 13h37
  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