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 :

std::unordered_set et std::hash


Sujet :

C++

  1. #1
    Membre tr�s actif
    Homme Profil pro
    �tudiant
    Inscrit en
    Avril 2012
    Messages
    538
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Par d�faut std::unordered_set et std::hash
    Bonjour,

    je souhaite cr�er une classe 'Ensemble' qui h�rite de 'std::unordered_set' :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    template<class T>
    class Ensemble : public std::unordered_set<T> {
        ...
    }
    J'ai plusieurs classe qui h�rite de la classe 'Element' :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    class A : public Element { ... }
    class B : public Element { ... }
    J'ai d�fini la fonction de Hashage pour 'Element' :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    namespace std {
        template <>
        struct hash<Element> {
            size_t operator()(const Element & e) const noexcept {
                return e.getId(); // Unique Id
            }
        };
    }
    Le probl�me c'est que je ne parviens pas � faire des ensemble de A ou B :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    int main() {
        Ensemble<Element> mySet_1; // Ok  
        Ensemble<A> mySet_2; // Pas Ok
    }
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    error: no match for call to '(const std::hash<A>) (const A&)'|
    Quelqu'un peut-il m'expliquer le fonctionnement de std::hash ? Ou est l'erreur ? Merci.

  2. #2
    Expert confirm�

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 033
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activit� : Software Developer
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par d�faut
    Salut!

    Pour commencer, les conteneurs de la STL ne sont pas fait pour faire partie d'un h�ritage (tu verras qu'il n'y a aucune fonction membre virtuelle dans ces classes).
    Je te conseille donc de mettre ton std::unordered_set en tant que membre de ta classe Ensemble, quitte � forwarder les fonctions dont tu as besoin (begin, end, find, insert...).

    Ensuite, pour ton probl�me, tu as d�fini un hash pour Element, mais pas pour A.
    Tu remarqueras qu'il te demande bien un std::hash< A >, cela ne tient pas compte de l'h�ritage que tu as mis en place.
    Tu peux le d�finir comme ceci, en utilisant ton std::hash< Element >:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    namespace std {
        template <>
        struct hash<A> {
            size_t operator()(const A & a) const noexcept {
                return hash<Element>()( a );
            }
        };
    }
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert � rien, mais qu'il est joli (des fois) : ProceduralGenerator (G�n�ration proc�durale d'images, et post-processing).

  3. #3
    R�dacteur/Mod�rateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : Canada

    Informations professionnelles :
    Activit� : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par d�faut
    Salut,

    bah l'erreur, le compilateur te l'indique, error: no match for call to '(const std::hash<A>) (const A&)'| que ne comprends-tu pas ?
    Il n'existe aucune fonction std::hash<A>.. et pourquoi faire un h�ritage de std::unordered_set ? C'est peu commun et peu recommand�.
    De m�me que ta fa�on d'utiliser un std::unordered_set. Il existe un param�tre template pour d�finir sa fonction de hash, pas besoin de sp�cialiser le param�tre par d�faut fourni par la std.
    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.

  4. #4
    Membre tr�s actif
    Homme Profil pro
    �tudiant
    Inscrit en
    Avril 2012
    Messages
    538
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Par d�faut
    Citation Envoy� par dragonjoker59 Voir le message
    Ensuite, pour ton probl�me, tu as d�fini un hash pour Element, mais pas pour A.
    Tu remarqueras qu'il te demande bien un std::hash< A >, cela ne tient pas compte de l'h�ritage que tu as mis en place.
    [/code]
    Oui j'ai bien compris. Mon but est de ne pas d�finir hash pour chaque classe : A, B, ... C'est pour cela que j'ai cr�� la classe Element. Comment faire ?

    En quoi l'h�ritage pose probl�me. J'ai besoin d'un objet std::unordered_set avec des m�thodes suppl�mentaires ... je n'ai pas le choix, non ?

  5. #5
    Membre tr�s actif
    Homme Profil pro
    �tudiant
    Inscrit en
    Avril 2012
    Messages
    538
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Par d�faut
    Est-ce correct comme ceci :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    struct HashElement {
        size_t operator() (const Element & e) const {
           return e.getId();
        }
    };
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    template<class T>
    class Ensemble : public std::unordered_set<T, HashElement> {
    ...
    }

  6. #6
    Expert confirm�

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 033
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activit� : Software Developer
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par d�faut
    A part pour l'h�ritage, oui.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert � rien, mais qu'il est joli (des fois) : ProceduralGenerator (G�n�ration proc�durale d'images, et post-processing).

  7. #7
    Invit�
    Invit�(e)
    Par d�faut
    Citation Envoy� par dragonjoker59 Voir le message
    A part pour l'h�ritage, oui.
    Quel est le probl�me avec cet h�ritage, s'il ne fait pas de polymorphisme ?

  8. #8
    Expert confirm�

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 033
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activit� : Software Developer
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par d�faut
    Ce la�us complet (bien qu'en anglais) devrait pouvoir r�pondre � ta question: http://stackoverflow.com/questions/6...110262#7110262
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert � rien, mais qu'il est joli (des fois) : ProceduralGenerator (G�n�ration proc�durale d'images, et post-processing).

  9. #9
    Invit�
    Invit�(e)
    Par d�faut
    Merci pour le lien. Je comprends les id�es d�fendues mais j'accroche moyen au raccourci qui ressort du laius comme quoi "composition = bien, h�ritage = pas bien", sans consid�ration du probl�me trait�. En plus, le gars nous �voque une th�orie cens�e le justifier mais il ne donne qu'un exemple en guise d'explication.

    Bref, pour en revenir � l'h�ritage en question, je pense qu'il peut �tre tout � fait valable s'il n'y a pas de polymorphisme ou de sous-h�ritage compliqu�s en jeu, et qu'il vaut mieux une solution simple qui r�pond juste au probl�me qu'une solution plus compliqu�e qu'on pourra r�utiliser "peut-�tre �ventuellement un jour".

  10. #10
    R�dacteur/Mod�rateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 38
    Localisation : Canada

    Informations professionnelles :
    Activit� : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par d�faut
    H�riter d'une classe juste pour en avoir l'interface (set, vector, list,...)
    - oui on en abuse parce que �a simplifie et acc�l�re les choses
    - �a reste un abus
    - on ne promeut pas une mauvaise pratique � un d�butant
    L'h�ritage �a indique un concept fort, ce n'est pas un gadget parce qu'on veut un push_back sur notre classe.
    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.

  11. #11
    Membre �clair�
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par d�faut
    H�riter d'une classe il ne faut le faire que lorsqu'il y a au moins une m�thode virtuelle sinon on s'expose � certains probl�mes:
    Si dans l'exemple suivant Foo h�rite de std::vector<int> alors le code suivant est syntaxiquement correct:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    std::vector<int>* p = new Foo;
    delete p; //<-- ici on seul le destructeur de std::vector<int> sera appelé; si Foo fait de l'allocation dynamique on aura un memory leak
    La solution si on souhaite r�cup�rer l'interface de std::vector � peu de frais c'est d'utiliser l'h�ritage priv� + les using:
    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
    #include <vector>
    #include <iostream>
     
    class Foo : private std::vector<int>
    {
        public:
        using std::vector<int>::size;
        using std::vector<int>::push_back;
    };
     
    int main() {
        Foo f;
        std::cout << f.size() << std::endl; //affiche 0
        f.push_back(3);
        std::cout << f.size() << std::endl; //affiche 1
    }

  12. #12
    Invit�
    Invit�(e)
    Par d�faut
    Citation Envoy� par CedricMocquillon Voir le message
    H�riter d'une classe il ne faut le faire que lorsqu'il y a au moins une m�thode virtuelle
    N'importe quoi. Dans ce cas, pourquoi le C++ ne met-il pas les m�thodes virtuelles par d�faut (comme en java, il me semble) ? Le polymophisme induit un co�t et une complexit� suppl�mentaires donc son utilisation doit se justifier.

    Et tant qu'on est dans le n'importe quoi, en quoi passer l'h�ritage en priv� est-il une solution aux fuites m�moires dans ton exemple ?

  13. #13
    Membre �clair�
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par d�faut
    Ho l�, doucement, il ne faut pas s'emporter; je n'ai peut �tre pas �t� assez clair dans mes explications de mon pr�c�dent post, je m'en excuse. Voil� un exemple complet: cpp.sh/6wjph
    Pour ceux qui ont la flemme d'aller voir le lien, voici l'exemple:
    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
    #include <vector>
    #include <iostream>
     
    class Foo : public std::vector<int>
    {
    public:
        Foo() {
            std::cout << "constructor call" << std::endl;
            data_ = new int[10];
        }
     
        ~Foo() {
            std::cout << "destructor call" << std::endl;
            delete[] data_;
        }
     
    private:
        int* data_;
    };
     
    int main() {
        std::vector<int>* p = new Foo;
        delete p;
    }
    Avec un h�ritage public d'une classe de base sans m�thode virtuelle (ce qui est le cas des classes conteneur de la STL), on ne voit affich� que "constructor call", ce qui implique donc une fuite m�moire puisque le d�sctructeur de Foo (celui qui lib�re data_) n'est pas appel�.
    Maintenant le m�me exemple avec un h�ritage priv�:
    le code:
    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
    #include <vector>
    #include <iostream>
     
    class Foo : private std::vector<int>
    {
    public:
        Foo() {
            std::cout << "constructor call" << std::endl;
            data_ = new int[10];
        }
     
        ~Foo() {
            std::cout << "destructor call" << std::endl;
            delete[] data_;
        }
     
    private:
        int* data_;
    };
     
    int main() {
        std::vector<int>* p = new Foo;
        delete p;
    }
    ben �a compile tout simplement pas! On a "main.cpp:22:31: error: 'std::vector<int>' is an inaccessible base of 'Foo'
    std::vector<int>* p = new Foo;"

    Maintenant c'est syntaxiquement possible et avec beaucoup de rigueur c'est possible de faire de l'h�ritage publique sans m�thode virtuelle mais pour moi c'est juste chercher un jour ou l'autre les ennuis (c'est comme faire appel au couple new / delete, c'est possible de le faire sans fuite m�moire mais aujourd'hui avec C++14 c'est reconnu qu'on peut d�velopper sans et qu'on s'en porte mieux)

  14. #14
    Invit�
    Invit�(e)
    Par d�faut
    D�sol� si je me suis emport� mais j'en ai un peu marre d'�tre pris pour un newbie parce que j'ai un avis diff�rent de certains (et pourtant partag� par d'autres).

  15. #15
    Membre �clair�
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par d�faut
    Non non y'a pas de soucis, c'est l'inconv�nient des forums: on ne sait pas quel est le ton employ� par les intervenants. C'est vrai que cela fait un moment que je n'�tais pas pass� sur le forum et que je ne connais pas les nouveaux (ou moins nouveaux ^^), mais il y a bien une diff�rence entre nouveau et newbie!
    Maintenant, bien que l'on ait un peu disgress� par rapport au post initial, je ne vois toujours pas dans quel cas c'est "utile" (je distingue "utile" de "�a permet de taper un moins de lignes de code" au d�triment potentiellement de la s�curit�) de faire de l'h�ritage public sans virtuelle dans la base; je m'explique:
    je vois plusieurs cas possibles:

    - on a une classe de base POD avec une d�riv�e elle m�me POD: on niveau m�moire l'h�ritage public est �quivalent � un membre:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct Base 
    { 
      int i; 
    };
     
    struct Derivee : public Base
    {
      double d;
    };
    est �quivalent en m�moire �
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    struct Base 
    { 
      int i; 
    };
     
    struct Derivee
    {
      Base b;
      double d;
    };
    La seule diff�rence c'est que l'on ne peut pas passer une derivee l� ou on attend une base mais syntaxiquement parlant on a juste � faire un ".b" pour r�soudre ce probl�me. S�mantiquement parlant je trouve �a "sain" puisqu'on est dans le cas de POD (souvent associ�s � des types "valeur") donc � mon sens on n'a pas � m�langer les choux et les carottes

    - on a une classe de base non POD et on veut juste "r�cup�rer" l'interface; dans ce cas, l'h�ritage priv� avec exportation de l'interface "utile" via les using permet �galement de ne pas m�langer les choux et les carottes (int�r�t de "�a ne compile pas" dans mon pr�c�dent post)

    - on veut m�langer les choux et les carottes (ou plut�t on une carotte �tant un l�gume on veut pouvoir passer des carottes l� o� on attend des l�gumes) dans ce cas on est dans le cas d'un polymorphisme dynamique et on a bien inter�t � utiliser une classe de base avec au minimum un destructeur virtuel sinon on peut avoir des memory leak (cf. mon pr�c�dent post). Note bien qu'on peut avoir des memory leak ou tout autre probl�me de lib�ration de ressource g�r� par les classes RAII.


    Maintenant j'ai "forg�" mon avis � partir de nombreuses lectures sur ce forum (grace notamment � des intervenant d'extr�me qualit� comme Luc, Emmanuel, Lo�c, Philippe et j'en oublie d'autre) et d'autres sources. C'est un avis qui peut �voluer mais il me faudrait un cas "concret" qui montre que "�a vaut le coup" sans engendrer de r�els probl�mes.

    Apr�s c'est au contraire tr�s bien que l'on ait des avis divergents c'est comme �a que l'on peut confronter les arguments pro / cons l'id�e �tant de ne pas "camper" sur nos positions mais de prendre en compte la rationnalit� des arguments avanc�s.

  16. #16
    Invit�
    Invit�(e)
    Par d�faut
    Ok pas de soucis; merci pour cette explication.

    Un exemple de cas o� j'utiliserais plut�t un h�ritage public sans fonction virtuelle, c'est justement un cas comme celui pr�sent� au d�but de la discussion : j'ai besoin d'un conteneur proche d'un des conteneurs de la STL mais avec quelques m�thodes en plus ou modifi�es; je vais utiliser ce nouveau conteneur directement (pas besoin de polymorphisme) et je n'ai pas d'allocation dynamique particuli�re � y ajouter. Ici, l'h�ritage public avec instanciation statique est simple, efficace et pas particuli�rement dangeureuse niveau m�moire.

    Apr�s oui, il y a plein d'autres cas o� ce ne sera pas suffisant donc c'est bien de le mentionner. Mais de l� � conseiller � un "d�butant" de sortir automatiquement l'artillerie lourde au cas o� on voudrait r�utiliser sur tous les probl�mes du monde, je pense que c'est un bon moyen de le convaincre de changer de langage.

  17. #17
    Expert confirm�

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 033
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activit� : Software Developer
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par d�faut
    Tout d�pend de ce qu'on consid�re comme l'artillerie lourde ^^'.
    Pour moi l'artillerie lourde, c'est l'h�ritage.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert � rien, mais qu'il est joli (des fois) : ProceduralGenerator (G�n�ration proc�durale d'images, et post-processing).

Discussions similaires

  1. la difference entre deux std::unordered_set
    Par mohsenuss91 dans le forum C++
    R�ponses: 7
    Dernier message: 21/04/2015, 17h30
  2. �quivalent de std::min et std::max en C?
    Par vdumont dans le forum C
    R�ponses: 2
    Dernier message: 08/10/2006, 18h15
  3. conversion std::string en std::istringstream
    Par flipper203 dans le forum SL & STL
    R�ponses: 3
    Dernier message: 06/07/2006, 18h34
  4. std::cout et std::wstring
    Par glKabuto dans le forum SL & STL
    R�ponses: 11
    Dernier message: 10/06/2006, 18h44
  5. std::sort() sur std::vector()
    Par tut dans le forum SL & STL
    R�ponses: 20
    Dernier message: 05/01/2005, 19h15

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