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 :

Table de hachage unordered_map et pointeurs vers objet ou objet, efficacité ?


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Homme Profil pro
    Développeur Programmation Fonctionelle
    Inscrit en
    Août 2019
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Programmation Fonctionelle
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 9
    Par défaut Table de hachage unordered_map et pointeurs vers objet ou objet, efficacité ?
    Bonjour,

    j'ai une classe Point3D<T> définie ainsi:

    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
    template <class T> class Point3D {
     
    public:
     
      T x,y,z; // coords 
     
     
      Point3D();
     
      ~Point3D();
     
      Point3D(T x,T y,T z);
     
      // copy constructor
      Point3D(const Point3D<T> &);
     
      // assignation operator
      Point3D<T> & operator=(const Point3D<T> &);
     
      // equality operator
      bool operator== (const Point3D<T> &);
     
    };
     
    #include "Point3D.cpp"

    Point3D.cpp contient entre autres ceci pour utilisation avec des unordered_map:

    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
    ...
     
     
    /* we need to specialize the hash function for our class
       because standart hash function works only with basic types
       such as string,int,etc...
    */
     
    // hash function for Point3D <-> Pixel
     
    template <class T> struct hash_point3d {
      size_t operator()(const Point3D<T> &p3d ) const
      {
        return hash<const Point3D<T> *>()(&p3d); // hash code is made with address !!!
      }
    };
     
     
    // equality test, mainly used with hash tables
    template <class T> struct point3DEquals : binary_function<const Point3D<T>&, const Point3D<T>&, bool> {
      bool operator()(  const Point3D<T>& lhs, const Point3D<T>& rhs ) const
      {
        return (&lhs == &rhs); // i compare the addresses !!!
      }  
    };     
     
    // equality operator
    template <class T> bool Point3D<T>::operator== (const Point3D<T> &p3d)  {
     
      return (x==p3d.x) && (y==p3d.y) && (z==p3d.z);
     
    }
     
    ...

    j'ai aussi une classe Point2D et je veux associer des Point3D projetés sur un plan en Point2D liés entre eux par une table de hachage, unordred_map pour commencer:

    je peux donc écrire cette définition :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    unordered_map<Point3D<float>,Point2D<int>,hash_point3d<float>,point3DEquals<float>> htPointPixel;
    et ça marche, mon code compile et fonctionne mais je me demande si j'aurai pas intérêt, dans un pur souci d'efficacité à définir ma table de hachage comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    unordered_map<Point3D<float> *,Point2D<int> *> htPointersPointPixel;
    j'ai l'impression que à l'exécution les pointeurs seront plus légers que des objets Point3D à manipuler (constructeur de recopie....etc)

    dans le code (coté développement) ce sera peut-être l'inverse et surement moins élégant.

    des opinions sur l'une ou l'autre de ces méthodes ?

    Damien

    PJ: la classe complète Point3D est en pièce jointe
    Fichiers attachés Fichiers attachés

  2. #2
    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
    Une classe Point3D est normalement très petite et la copie ne sera pas trop grave.
    Tu devrais la passer en const& de toute façon.
    Les pointeurs seront plus rapide si tu les transites partout, mais il y a forcément un objet bien réel quelque part sur lequel tu pointes.
    Donc pour chaque pointeur sur T tu as sizeof(T) + sizeof(T*) occupé.
    Imo, aucun intérêt dans ton cas.

    Aussi, on ne fait jamais d'include de cpp dans un cas normal. Les implémentations de template doivent être dans un fichier inlus (les cpp sont normalement compilés par ton IDE déjà), généralement on retrouve les extensions .tpl ou .inl.
    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
    Membre habitué
    Homme Profil pro
    Développeur Programmation Fonctionelle
    Inscrit en
    Août 2019
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Programmation Fonctionelle
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 9
    Par défaut
    pour l'include du cpp c'est apres un mois de galere sans include que j'en suis arrivé à celà, je sais que ça force le compilo a tout avaler d'un coup et c'est pas top mais quand on utilise des template et la STL c'est la seule solution que j'ai trouvé avec gcc sinon il n'a pas assez d'info à partir du header pour compiler le code.C'est pas faute d'avoir essayer.
    Mais je reconnais c'est pas la façon de coder en C++ que j'avais il y a 20 ans... mais je faisais pas de template et le langage étais different... j'ai vu plein de sujet ailleurs sur ce probléme, mais si tu as une solution qui marche je suis preneur?

    pour en revenir au sujet, je crois quand même que les pointeurs seront plus legers, pour comprendre pourquoi c'est parceque j'utilise une classe Univers avec une liste à parcourir pour savoir si le point3D existe déjà ,et je les veux unique:

    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
    // Universe Class
    // Damien MATTEI
     
    #ifndef UNIVERSE_HPP
    #define UNIVERSE_HPP
     
     
     
     
    template <class T> class Universe {
     
    public:
     
      // data 
      list < Point3D<T> *> point3DptrList;
     
     
      Universe();
     
      ~Universe();
     
      Point3D<T> * createPoint3Dptr(T x,T y,T z); // create a point by checking if it already exist
     
    };
     
    #include "Universe.cpp"
     
    #endif /* UNIVERSE_HPP */
    et mon code Universe.cpp:

    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
    // Universe Class
    // Damien MATTEI
     
    #include "Point3D.hpp"
    #include "Universe.hpp"
     
    #include "debug.hpp"
     
    // implementations
     
    template <class T> Universe<T>::Universe() {
     
     
    #ifdef DISPLAY_CONSTRUCTOR
      cout << "# Universe constructor # " << this << endl;
    #endif
    }
     
    template <class T> Universe<T>::~Universe() {
     
    #ifdef DISPLAY_CONSTRUCTOR
      cout << "# Universe destructor # "  << this << endl;
    #endif
     
    }
     
     
     
     
    template <class T> ostream&  operator<< (ostream &out, Universe<T> &u)
    {
     
      out << "Universe("  
          << u
          << ")"
        ;
     
      return out;
     
    }
     
     
    // create a point by checking if it already exist in the universe
    template<class T> Point3D<T> * Universe<T>::createPoint3Dptr(T x,T y,T z) {
     
      DEBUG(cerr << "Universe<T>::createPoint3Dptr" << endl;)
      Point3D<T> * pt3d_ptr = new Point3D<T>(x,y,z);
      Point3D<T> & pt3d = *pt3d_ptr;
     
     
      DEBUG(cerr << "Universe<T>::createPoint3Dptr : std::find_if ... " << endl;)
      // i check unicity of the point in Universe i.e to save memory and speed i do not want to have two mathematically identical 3D points
      typename list< Point3D<T> *>::iterator iterP3Dptr = std::find_if(point3DptrList.begin(), point3DptrList.end(),
    								   [&pt3d](Point3D<T> * pt3d_ptr_lambda_param)
    								   { DEBUG(cerr << "Universe<T>::createPoint3Dptr : in Lambda" << endl;)
    								     return  *pt3d_ptr_lambda_param == pt3d; });
     
      DEBUG(cerr << "Universe<T>::createPoint3Dptr : bool found ... " << endl;)
      bool found = (iterP3Dptr != point3DptrList.end());
     
      // we have to add the point to the universe
      if (found) {
          pt3d.~Point3D<T>();
          return *iterP3Dptr; // return the pointer to Point3D
        }
      else {
        DEBUG(cerr << "Universe<T>::createPoint3Dptr : point3DptrList.push_back(pt3d_ptr);" << endl;)
        point3DptrList.push_back(pt3d_ptr);
        return pt3d_ptr;
      }
     
    }
    donc au final par rapport à du code C l'elegance du C++ est de masquer l'utilisation des pointeurs avec des references comme ici:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Point3D<T> * pt3d_ptr = new Point3D<T>(x,y,z);
      Point3D<T> & pt3d = *pt3d_ptr;
    ou dans mon main:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Universe<float> univ;
     
      cout << " avec des pointeurs et des references vers des point3D " << endl;
     
      Point3D<float> * pt3d_uniq_ptr = univ.createPoint3Dptr(1,0,0);
     
      Point3D<float> & pt3d_uniq_ref = *pt3d_uniq_ptr;
     
      cout << "pt3d_uniq_ref : " << pt3d_uniq_ref << endl;
     
      Point3D<float> * pt3d_uniq_ptr2 = univ.createPoint3Dptr(1,0,0);
     
      Point3D<float> & pt3d_uniq_ref2 = *pt3d_uniq_ptr2;
    mais ça surcharge un peu le code et la mémoire car on voit bien que je dois creer l'objet avec un pointeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point3D<float> * pt3d_uniq_ptr = univ.createPoint3Dptr(1,0,0);
    et ensuite je le manipule avec une réference pour la lisibilité:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point3D<float> & pt3d_uniq_ref = *pt3d_uniq_ptr;

  4. #4
    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
    Plus de code et plus d'erreurs de code..
    On ne fait jamais d'appel explicite au destructeur. Ton truc fait une fuite mémoire si le point existe déjà.
    Non tu n'as aucun intérêt à utiliser de pointeur ici. Non un pointeur n'est pas plus léger. Je t'ai déjà montré qu'un pointeur prend plus de place en mémoire que l'object seul...
    Ta classe Point est ridiculement petite et sera copiée/déplacée sans faire sourciller le moindre CPU.
    Si t'en es à inclure des cpp c'est ta configuration et ton setup qui sont bancales.
    Et pour avoir une collection d'objets unique, il existe std::set.
    Avec une list les pointeurs sont superflus, les éléments ne sont pas désalloués sur les opérations de push_back etc. Avec un vector tu aurais plus de soucis et un pointeur pourrait éventuellement être une solution, et encore, c'est possible que tu sois juste dans l'erreur totale et ne saches pas voir une autre solution meilleure.
    Et même si tu venais à devoir utiliser des pointeurs, ce serait avec des std::unique_ptr.
    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.

  5. #5
    Membre habitué
    Homme Profil pro
    Développeur Programmation Fonctionelle
    Inscrit en
    Août 2019
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Programmation Fonctionelle
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 9
    Par défaut
    visiblement vous lisez pas bien le code , je crée des points unique donc...
    je le detruit moi meme quand la variable intermediaire ne sera pas utilisée,sinon je le garde, apres que je laisse faire ça au compilateur est une possibilité aussi.
    c'est pas clair ce que vous dites sur push_back , je n'ai rien a desaloouer , je stocke justement que le pointeur et non pas l'objet donc pas de recopie inutile, vous comprenez visiblement pas bien le code.
    set est prévu dans une future implementation, je fais des tests comparatifs justement sur la rapidité et l'efficacité, c'est pour ça que je commence par des list et des unordered_set au depart.

  6. #6
    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
    Je lis le code, et à l'inverse de toi je semble le comprendre.
    Je vois pt3d.~Point3D<T>();, ceci n'est pas une désallocation de pointeur.
    Pointeur non désalloué, donc fuite mémoire. Peut-être devrais-tu (re)voir ta compréhension du code.
    Si tu veux juste insulter en présentant un code médiocre, je vais pas perdre plus de temps sur ton problème.
    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.

  7. #7
    Membre habitué
    Homme Profil pro
    Développeur Programmation Fonctionelle
    Inscrit en
    Août 2019
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Programmation Fonctionelle
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 9
    Par défaut
    FYI si je commente le destructeur... le point n'est jamais désalloué, voilà pourquoi j'utiilse new et ensuite détruit l'objet, il y aurait une fuite de mémoire au contraire si je ne le faisait pas.

    je peux pas vous montrer l'absence de destruction si elle etais pas faite manuellement puisque justement le destructeur n'est PAS apellé par le code automatiquement mais par contre quand j'apelle le destructeur je le voit bien en mode debug:
    ----------- test Universe ------------------
    # Universe constructor # 0x7ffeeafc3518
    avec des pointeurs et des references vers des point3D
    Universe<T>::createPoint3Dptr
    # Point3D constructor # P3D 0x7fef35400350 (1, 0, 0)
    Universe<T>::createPoint3Dptr : std::find_if ...
    Universe<T>::createPoint3Dptr : bool found ...
    Universe<T>::createPoint3Dptr : point3DptrList.push_back(pt3d_ptr);
    pt3d_uniq_ref : P3D 0x7fef35400350 (1, 0, 0)
    Universe<T>::createPoint3Dptr
    # Point3D constructor # P3D 0x7fef354027d0 (1, 0, 0)
    Universe<T>::createPoint3Dptr : std::find_if ...
    Universe<T>::createPoint3Dptr : in Lambda
    Universe<T>::createPoint3Dptr : bool found ...
    # Point3D destructor # 0x7fef354027d0
    pt3d_uniq_ref2 : P3D 0x7fef35400350 (1, 0, 0)
    --------------------------------------------

    0x7fef354027d0 est bien détruit.

  8. #8
    Membre habitué
    Homme Profil pro
    Développeur Programmation Fonctionelle
    Inscrit en
    Août 2019
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Programmation Fonctionelle
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 9
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Une classe Point3D est normalement très petite et la copie ne sera pas trop grave.
    Tu devrais la passer en const& de toute façon.
    Les pointeurs seront plus rapide si tu les transites partout, mais il y a forcément un objet bien réel quelque part sur lequel tu pointes.
    Donc pour chaque pointeur sur T tu as sizeof(T) + sizeof(T*) occupé.
    ??? un pointeur est une adresse,un nombre , ça prends moins de place qu'une structure ou l'instanciation d'un objet d'une classe, meme si Point3D peut se resumer à 3 nombres,il s'agit d'un exemple, en general un objet de classe peut etre bien plus gros
    Citation Envoyé par Bousk Voir le message
    Imo, aucun intérêt dans ton cas.

    Aussi, on ne fait jamais d'include de cpp dans un cas normal. Les implémentations de template doivent être dans un fichier inlus (les cpp sont normalement compilés par ton IDE déjà), généralement on retrouve les extensions .tpl ou .inl.

  9. #9
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    On n'appelle jamais directement le destructeur. En effet l'appeler détruit bien l'objet (c'est ce que tu vois au debug), mais il faut non seulement détruire mais aussi libérer la mémoire.
    Ce qu'il faut appeler c'est delete unPointeur; ou delete[] unTableau;, ça va détruire l'objet ET libérer la mémoire (vérifie en debug que le destructeur est finalement appelé ou déroule l'exemple de jo_link_noir)

    Ça a été dit plusieurs fois, désolé pour la redite mais comme c'est une base pour débuter...

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

Discussions similaires

  1. Pointeur vers objet dans un vecteur
    Par julieng31 dans le forum C++
    Réponses: 3
    Dernier message: 27/09/2013, 09h29
  2. Réponses: 5
    Dernier message: 21/06/2013, 21h13
  3. Passage de tableau de pointeurs vers objets
    Par gnulix dans le forum C++
    Réponses: 5
    Dernier message: 14/04/2007, 19h41
  4. Réponses: 4
    Dernier message: 04/02/2007, 00h06

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