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 :

l'operator == doit être implementé ?


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Par défaut l'operator == doit être implementé ?
    Bonsoir

    J'aimerai savoir pourquoi l'operateur == n'est pas déduit automatiquement par le compilateur (comme par exemple l'operateur d'affectation, le constructeur par recopie), même dans un cas trivial ?

    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
    class Foo
    {
       std::string m_str;
       int         m_value;
     
    public:
       Foo(const std::string& str, int value)
       : m_str(str)
       , m_value(value)
       {
       }
     
       bool operator == (const Foo& other) {
          return m_str == other.m_str && m_value == other.m_value;
       }
     
       const std::string& GetString() const { return m_str; }
     
       int GetValue() const { return m_value; }
    };
    Si je n'implemente pas l'operator==, je ne peux pas supprimer un element d'une liste de Foo :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int main(int argc, char **argv)
    {
       typedef std::list<Foo> ListFoo;
       ListFoo listFoo;
     
       listFoo.push_back( Foo("1", 0) );
       listFoo.push_back( Foo("2", 0) );
       listFoo.push_back( Foo("3", 0) );
       listFoo.push_back( Foo("3", 1) );
     
       listFoo.remove( Foo("3", 0) );
       return 0;
    }
    Avec l'operator == implementé, pas de problèmes. Sans, j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error: no match for 'operator==' in '__first.std::_List_iterator<_Tp>::operator* [with _Tp = Foo]() == __value'
    Ce qui me parait surprenant, c'est qu'il faille implémenter cet opérateur dans le cas trivial de variables membres ayant toutes l'operator== de défini.
    Avez vous une explication, ou bien c'est juste pour forcer le developpeur à expliciter cet operateur (dans ce cas, pourquoi ne pas faire la même chose pour l'operateur= et le constructeur par recopie ?).
    --
    Jérémie

  2. #2
    Membre Expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Par défaut
    rien de dit que l'égalité de deux objet se fait par la comparaison strict de chacun de ses membres.

    pour la chaine par exemple tu pourrais ne pas etre sensible a la casse (minuscule/majuscule)

  3. #3
    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és le moment où tu crées une structure manipulant plusieurs valeurs, il existe un nombre de possibilités de comparaison équivalent à +/- la factorielle du nombre de valeurs utilisées.

    Ainsi, si tu as, par exemple, une structure contenant deux membres, tu peux vouloir évaluer l'égalité:
    1. en ne te basant que sur le premier membre
    2. en ne te basant que sur le deuxième membre
    3. en te basant sur les deux membres pris séparément
    4. (voire) en te basant sur un calcul particulier effectué avec les deux membres

    En effet, ce n'est pas parce que tu utilise deux valeurs dans une structuresou parce que les deux valeurs peuvent chacune subir une comparaison d'égalité que les deux valeurs sont obligatoirement nécessaires pour te permettre d'effectuer une comparaison d'égalité

    Il "suffit" par exemple que l'une ou l'autre valeur de la structure agisse comme un "buffer" (qui permet de savoir s'il faut ou non recalculer quelque chose) pour qu'il n'y ait plus aucun sens à utiliser cette valeur pour tester l'égalité.

    Dés lors, plutôt que de se dire que le "cas général" (qui n'en est, en pratique rarement un) est de comparer tous les membres un à un, l'optique a été prise de forcer la définition des opérateurs de comparaison (car cela s'applique également à >, >=, < et <= ) si, d'aventure, tu en as besoin
    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

  4. #4
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Par défaut
    Merci pour vos réponses

    @jabbounet : la chaine de caractères est (à mon avis) un mauvais exemple, vu que pour l'ensemble des classes string que je connais (std::[w]string, wxString, QString, CString), l'opérateur == est toujours implémenté. Mais je pinaille

    @Koala01 : Je (tu) pourrais argumenter la même chose pour l'opérateur =, et pour le constructeur par recopie, qui sont automatiquement déduis par le compilateur si on ne les implémente pas. Au fait, le défi de ta signature est terminé ... Vivement le prochain.
    --
    Jérémie

  5. #5
    Membre Expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Par défaut
    Citation Envoyé par jfouche Voir le message
    Merci pour vos réponses

    @jabbounet : la chaine de caractères est (à mon avis) un mauvais exemple, vu que pour l'ensemble des classes string que je connais (std::[w]string, wxString, QString, CString), l'opérateur == est toujours implémenté. Mais je pinaille
    crois tu, prenons un exemple bebete je te croise dans la rue je t'appelle je dit ton nom. saura tu faire la distinction si je le dis en minuscule ou en majuscule?

    tu fais une recherche dans un fichier ta comparaison se fait de quelle façon, (en général dans la pluspart des editeurs tu as un case à cocher pour rendre ta recheche case sensitive)?

    donc ok il y'a des comparaison par défaut dans les strings, mais sont ils toujours adaptés aux besoin?

  6. #6
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Soit dit en passant, changé la sensibilité à la casse avec string ça se fait via la classe de trait char_trait.

  7. #7
    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
    Citation Envoyé par jfouche Voir le message
    @Koala01 : Je (tu) pourrais argumenter la même chose pour l'opérateur =, et pour le constructeur par recopie, qui sont automatiquement déduis par le compilateur si on ne les implémente pas.
    Non, pas vraiment...

    Car les opérateurs de comparaison ne pourraient avoir un comportement trivial que pour les structure ayant réellement sémantique de valeur.

    Ainsi, une chaine de caractères (std::string) n'étant rien de plus qu'un certain nombre de... caractères, tu te trouve face à une structure qui a bel et bien une sémantique de valeur (parce que philippe est différent de pascal )

    Or, les structures ayant réellement sémantique de valeur sont, en définitive, très largement minoritaires dans une conception classique

    Il ne serait donc pas cohérent d'adopter un comportement par défaut (dont on peut raisonnablement penser qu'il est en mesure de s'adapter au "plus grand nombre") qui, en pratique, ne s'applique qu'à une minorité de cas

    Par contre, le constructeur par copie et l'opérateur d'affectation gardent tout leur sens, même pour les structures ayant sémantique d'objet... Du moins, tant que tu n'a pas de raison valable d'y renoncer.

    Si tu copie n'importe quel objet, même si un des membres venait à servir de "buffer" permettant, par exemple, de signifier qu'une propriété de l'objet doit être recalculée, la copie présente bel et bien les mêmes caractéristique que l'objet copié: si la propriété "calculée" ne doit pas être (re)calculée pour l'objet original, elle ne doit pas non plus l'être pour la copie

    Et le raisonnement s'applique également à l'opérateur d'affectation (et ce d'autant plus qu'il utilise régulièrement l'idiome copy and swap, afin d'assurer la libération correcte des ressources)
    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

  8. #8
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par jfouche Voir le message
    @koala : t'es sur que c'est la factorielle? intuitivement, si une classe a N données membres, j'aurais tendance à penser que chaque membre peut ou ne peut pas être pris en compte par l'opérateur égalité. Ca nous donne donc 2 possibilités par membre, ou 2^N opérateurs... C'est exponentiel, mais "moins" que la factorielle (qui, elle, est plutôt en 2 ^ N log(N))
    En comparaison "simple", tu as effectivement 2*N possibilités, au temps pour moi.

    Ceci dit, si tu te base sur le principe que la comparaison peut être effectuée sur base d'un calcul quelconque basé sur les différents membres, le nombre de possibilité explose littéralement

  9. #9
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Citation Envoyé par jfouche
    @koala : t'es sur que c'est la factorielle? intuitivement, si une classe a N données membres, j'aurais tendance à penser que chaque membre peut ou ne peut pas être pris en compte par l'opérateur égalité. Ca nous donne donc 2 possibilités par membre, ou 2^N opérateurs... C'est exponentiel, mais "moins" que la factorielle (qui, elle, est plutôt en 2 ^ N log(N))
    En comparaison "simple", tu as effectivement 2*N possibilités, au temps pour moi.

    Ceci dit, si tu te base sur le principe que la comparaison peut être effectuée sur base d'un calcul quelconque basé sur les différents membres, le nombre de possibilité explose littéralement
    Allo ? Ici la terre, je crois qu'il y a un faille spatio-temporelle quelque part Je ne vois pas d'où cela sort... C'est bô l'informatique

    En tout cas, merci à tous, je crois que c'est plus clair désormais
    --
    Jérémie

  10. #10
    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
    oupppsss...

    Apparemment, j'ai édité (sans le vouloir) l'intervention de jfouche que je voulais en réalité citer

    jfouche, je te fais mes plus plates excuses, le problème, c'est que j'ai du coup perdu ton intervention d'origine...

    Si tu veux la remettre, je ferai attention par la suite
    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

  11. #11
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par jfouche Voir le message
    Allo ? Ici la terre, je crois qu'il y a un faille spatio-temporelle quelque part Je ne vois pas d'où cela sort... C'est bô l'informatique
    Oui en fait, c'est moi qui ait été mutilé par Koala... (sans rancune koala)

    Ce que je disais, c'est que la principale raison est un principe d'économie: ne pas générer de code inutile. Créer par défaut un opérateur égalité signifiait beaucoup de code inutile (il ne sert pas toujours, loin sans faut).


    Pour le constructeur de copie et l'affectation, en revanche, je crois qu'on n'a pas le choix. Si on veut que les classes se comportent comme les types natifs, il faut définir un constructeur et un destructeur par défaut, sinon on ne peut écrire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void ma_fonction() {
      maClasse X;
     // quelque chose
    }
    Mais si l'on veut pouvoir utiliser maClasse comme paramètre ou valeur de retour d'une fonction, vu que le C++ passe ses arguments par copie, il va (forcément) falloir un constructeur de copie, et probablement un opérateur d'affectation (en fait pas forcément pour ce dernier, mais bon, c'est quand même plus sain de le définir). Sinon, on ne pourra écrire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ma Classe ma_fonction(maClasse X) {
      maClasse res;
      // du code ici
      return res;
    }
    En résumé, sans les constructeurs et les opérateurs d'affectation, certaines constructions de base du langage ne fonctionneront pas avec les types utilisateurs "de base" (les POD). Et oui, comme disait Luc, cette notion de "copie de base" est présente en C, donc il y a aussi une idée de rétrocompatibilité planquée derrière.

    Pour l'égalité et autres opérateurs, il n'y a pas d'obligation, et là c'est le principe d'économie qui s'applique.


    Ma remarque à Koala, à laquelle il a répondu, c'était qu'a priori, si on a N membres dans une classe, les opérateurs égalités possibles seront de l'ordre de 2^N, puisqu'on devra choisir, pour chaque membre, s'il est pris en compte ou non pour la détermination de l'égalité. C'est exponentiel, mais moins "fortement" que la factorielle qui elle est de l'ordre de 2^(n log(n) )

    Francois

  12. #12
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Ce que je disais, c'est que la principale raison est un principe d'économie: ne pas générer de code inutile. Créer par défaut un opérateur égalité signifiait beaucoup de code inutile (il ne sert pas toujours, loin sans faut).
    As-tu une référence pour cette affirmation?

    Les seuls membres générés par le compilateur sont ceux qui correspondent à des opérations disponibles sur les structs du C. Je ne crois pas qu'il faille aller chercher plus loin.

    (Note: la proposition qui introduit =default en C++0X signale qu'elle serait utilisable pour les opérateurs d'égalité, mais suggère de s'abstenir de le faire pour le moment. J'ai pas le souvenir qu'elle n'ait pas été suivie. Il y a eu une proposition pour utiliser =default avec swap; j'ai pas suivi si elle a été acceptée ou pas.)

  13. #13
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Citation Envoyé par jfouche Voir le message
    J'aimerai savoir pourquoi l'operateur == n'est pas déduit automatiquement par le compilateur (comme par exemple l'operateur d'affectation, le constructeur par recopie), même dans un cas trivial ?
    Pour des problèmes de retro-compatibilité avec le C ? Il faudrait regarder dans le D&E s'ils en parlent.

    Par défaut l'affectation était fournie sur les structures dans mes souvenirs -- ce qui était un moyen de retourner un tableau statique non local. Mais pas l'égalité.

    Personnellement, j'aurais préféré que copie et affectation ne soit pas fournies par défaut. Mais il est maintenant trop tard pour changer. Il me semble qu'il y avait eu des discussion à ce sujet dans le cadre du prochain standard.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  14. #14
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Février 2006
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 153
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    Personnellement, j'aurais préféré que copie et affectation ne soit pas fournies par défaut.
    Je suis d'accord. Cela obligerai le développeur à les implémenter, ce qui permettrai à bon nombre de ne pas se faire coincer par une variable membre pointeur (dont moi une fois, ce qui m'a permis de comprendre qu'ils pouvaient être appelé sans qu'on sans rende compte, via les containers de la STL par exemple, ou bien lors d'un retour par valeur ou passage de paramètre par valeur).
    Mais il faut être honnête, je ne les implémente pas systématiquement, notamment lors de classes simple...
    --
    Jérémie

  15. #15
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    Mais il faut être honnête, je ne les implémente pas systématiquement, notamment lors de classes simple...
    Encore heureux. Dans le cas d'une classe à sémantique de valeur (donc qui a un sens à être copiée) où tous les membres sont copiables sans soucis (cad pas de pointeur) ré-écrire le constructeur par copie c'est une perte de temps et d'énergie (et p-e même un source de bug potentiel si on rajoute des membres et qu'on n'édite pas le constructeur) alors que le compilateur le fait très bien tout seul.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

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

Discussions similaires

  1. Pourquoi le scanf doit être interdit
    Par gnto dans le forum C
    Réponses: 4
    Dernier message: 14/06/2006, 14h54
  2. [WebForms]A quel endroit doit-être présent le framework ?
    Par HULK dans le forum Général Dotnet
    Réponses: 2
    Dernier message: 13/04/2006, 14h59
  3. [Client/Serveur]Où doit être mis outil mesure Performances?
    Par sabure dans le forum Décisions SGBD
    Réponses: 4
    Dernier message: 06/03/2006, 23h52
  4. Réponses: 4
    Dernier message: 24/02/2006, 11h50
  5. dans un CSS que le texte doit être souligé?
    Par hstlaurent dans le forum Mise en page CSS
    Réponses: 1
    Dernier message: 01/09/2005, 16h06

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