Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
3032 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  Gestion des pointeurs sur instance

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Gestion des pointeurs sur instance

n°2192511
Terminapor
I'll see you rise.
Posté le 02-06-2013 à 00:37:16  profilanswer
 

Bonsoir :hello:

 

Je cherche le type de pointeur le plus approprié pour gérer des instances d'une collection, en gros :

 

J'ai une class qui contrôle des objets pour un moteur de rendu, elle gère leur cycle de vie (allocation, suppression).
ce que je voudrais, c'est avoir le type de pointeur le plus approprié pour gérer les pointeurs sur ces objets, un comportement comme celui-ci :

Code :
  1. type* P = new type;
  2. type* rP = &P;
  3. delete P;
  4. *rP; // <- Ici, déclencher par exemple une exception
 

J'avais fait une implémentation assez truellique de ce genre de système, où les "vrais" pointeur (P dans ce cas) avaient en attribut une liste de tout les pointeurs qui pointaient sur lui, et lorsqu'il était supprimé, je rendait les autres pointeurs invalide, mais ça me semble pas très adapté. (Au pire, je peux activer ce système uniquement en debug..)

 

Merci pour votre aide :jap:

 

edit : Je viens de penser au sf::Resource_ptr de la SFML, j'ai regardé le code source et c'est la même chose que ma version truellique, donc c'est le seul moyen de faire ? :sweat:


Message édité par Terminapor le 02-06-2013 à 00:52:33

---------------
Perhaps you don't deserve to breathe
mood
Publicité
Posté le 02-06-2013 à 00:37:16  profilanswer
 

n°2192531
Terminapor
I'll see you rise.
Posté le 02-06-2013 à 13:23:02  profilanswer
 

Je up le topic, j'ai pondu un code :D

 

Donc, le système vérifie que les pointeurs sont valides / mettent à jour la liste uniquement si SAFEPOINTERS est défini, niveau perfs ça donne :

 

Benchmark (SafePointers enabled) :
Performed in 85.3783 ms.
Benchmark (SafePointers disabled) :
Performed in 4.22425 ms.
Benchmark (Naked Pointers) :
Performed in 2.01364 ms.

 

Et voilà le code de la class :

 
Code :
  1. #ifndef _REFERENCEPOINTER_HPP_
  2. #define _REFERENCEPOINTER_HPP_
  3. #include <iostream>
  4. #ifdef SAFEPOINTERS
  5.     #include <set>
  6. #endif
  7. namespace Core
  8. {
  9.     class NullPointerException : public std::exception
  10.     {
  11.         virtual const char* what() const throw()
  12.         {
  13.             return "NullPointer Exception";
  14.         }
  15.     };
  16. // forward declaration :
  17. template<typename T>
  18. class WatcherPointer;
  19. // Unique pointer, owns the element :
  20. template <typename T>
  21. class OwnerPointer
  22. {
  23.  private:
  24.   T* Value;
  25.   // Disable copy :
  26.   OwnerPointer(const OwnerPointer & Other);
  27.   OwnerPointer& operator = (const OwnerPointer& Other);
  28.   #ifdef SAFEPOINTERS
  29.   mutable std::set<WatcherPointer<T>*> WatcherList;
  30.   void Add(WatcherPointer<T>* New)
  31.   {
  32.    WatcherList.insert(New);
  33.   }
  34.   void Remove(WatcherPointer<T>* Ptr)
  35.   {
  36.    WatcherList.erase(Ptr);
  37.   }
  38.   #endif
  39.  public:
  40.   OwnerPointer()
  41.   {
  42.    Value = NULL;
  43.   }
  44.   OwnerPointer(T* Value)
  45.   {
  46.    this->Value = Value;
  47.   }
  48.   T& operator *()
  49.   {
  50.       #ifdef SAFEPOINTERS
  51.    if (!Value)
  52.     throw NullPointerException();
  53.                            #endif
  54.                             return (*Value);
  55.   }
  56.   T* operator->()
  57.   {
  58.       #ifdef SAFEPOINTERS
  59.    if (!Value)
  60.     throw NullPointerException();
  61.                             #endif
  62.                              return Value;
  63.   }
  64.   operator bool() const
  65.   {
  66.       return (Value != NULL);
  67.   }
  68.   ~OwnerPointer()
  69.   {
  70.    #ifdef SAFEPOINTERS
  71.     for (typename std::set<WatcherPointer<T>*>::iterator it = WatcherList.begin(); it!= WatcherList.end(); ++it)
  72.     {
  73.      WatcherPointer<T> * Ptr = (*it);
  74.      Ptr->Reference = NULL;
  75.     }
  76.    #endif
  77.    delete Value;
  78.   }
  79.  friend class WatcherPointer<T>;
  80. };
  81. // Points to an existing owner :
  82. template <typename T>
  83. class WatcherPointer
  84. {
  85.  private:
  86.   OwnerPointer<T>* Reference;
  87.  public:
  88.   WatcherPointer()
  89.   {
  90.    Reference = NULL;
  91.   }
  92.   explicit WatcherPointer(OwnerPointer<T>* Reference)
  93.   {
  94.    this->Reference = Reference;
  95.    #ifdef SAFEPOINTERS
  96.    if (Reference)
  97.     Reference->Add(this);
  98.    #endif
  99.   }
  100.   explicit WatcherPointer (const WatcherPointer<T> &Other)
  101.   {
  102.    Reference = Other.Reference;
  103.    #ifdef SAFEPOINTERS
  104.    if (Reference)
  105.     Reference->Add(this);
  106.    #endif
  107.   }
  108.   WatcherPointer<T> & operator = (const WatcherPointer<T> &Other)
  109.   {
  110.    #ifdef SAFEPOINTERS
  111.    if (Reference)
  112.     Reference->Remove(this);
  113.    #endif
  114.    Reference = Other.Reference;
  115.    #ifdef SAFEPOINTERS
  116.    if (Reference)
  117.     Reference->Add(this);
  118.    #endif
  119.    return (*this);
  120.   }
  121.   WatcherPointer<T> & operator = (OwnerPointer<T>* NewRef)
  122.   {
  123.    #ifdef SAFEPOINTERS
  124.    if (Reference)
  125.     Reference->Remove(this);
  126.    #endif
  127.    Reference = NewRef;
  128.    #ifdef SAFEPOINTERS
  129.    if (Reference)
  130.     Reference->Add(this);
  131.    #endif
  132.    return (*this);
  133.   }
  134.   T& operator *()
  135.   {
  136.       #ifdef SAFEPOINTERS
  137.    if (!Reference)
  138.     throw NullPointerException();
  139.                             #endif
  140.                             return *(Reference->Value);
  141.   }
  142.   T* operator->()
  143.   {
  144.       #ifdef SAFEPOINTERS
  145.    if (!Reference)
  146.     throw NullPointerException();
  147.                          #endif
  148.                          return (Reference->Value);
  149.   }
  150.             operator bool() const
  151.   {
  152.       return (Reference && Reference->Value != NULL);
  153.   }
  154.  friend class OwnerPointer<T>;
  155. };
  156. }
  157. #endif
 

Si vous avez des conseils pour améliorer la qualité du code ou la vitesse d'exécution, je suis preneur :jap:

 

edit : Désolé, j'arrive pas à avoir la bonne mise en page, y'a des lignes qui sont très mal foutu :(


Message édité par Terminapor le 02-06-2013 à 13:25:12

---------------
Perhaps you don't deserve to breathe
n°2192539
Joel F
Real men use unique_ptr
Posté le 02-06-2013 à 16:17:31  profilanswer
 

deja utilisait un ruc ecrit proprement genre boost::shared_ptr me parait mieux que d'ecrire une n-ieme classe de gestion de pointeurs.
 
Voir aussi si unique_ptr n'est pas plus adapté.

n°2192541
Terminapor
I'll see you rise.
Posté le 02-06-2013 à 16:37:35  profilanswer
 

Mais si j'ai bien compris, les shared_ptr ont un système de comptage de références, et dès que ça atteint 0 l’élément est supprimé.
Or moi, je veux que si le propriétaire de la variable la supprime, tout les pointeurs sont automatiquement mis à NULL (Ce qui se passe dans ma class WatcherPointer en gros).
 
Pour ce qui est de unique_ptr, c'est pas juste un pointeur qu'on ne peut pas copié et qui est supprimé lors de la fin de son cycle ?


---------------
Perhaps you don't deserve to breathe
n°2192640
Terminapor
I'll see you rise.
Posté le 03-06-2013 à 18:46:14  profilanswer
 

Ok je viens de voir qu'en fait, y'avait les std::weak_ptr qui permettent de faire plus ou moins ce que je veux.
En gros, si j'ai bien compris, les weak_ptr sont comme des shared_ptr sauf qu'ils n'incrémentent pas le nombre de références, et dès lorsque que le tout les shared_ptr sont reset, ils sont marqués comme expirés c'est ça ?

 

Mais le soucis, c'est que pour modifier une valeur du pointeur (ou simplement lire), il faut absolument régénérer un shared_ptr à partir du weak_ptr, et ça serait chiant à mettre en place un système pour bypasser toute la vérification des pointeurs lors de la compilation en release. :/

 

edit : D'un autre côté, le fait de devoir régénérer un shared_ptr fait que je suis sûr à 100% qu'en cas d'usage sur un thread séparé, mon pointeur sera valide et ne pourra pas être supprimé lors d'un appel de fonction..


Message édité par Terminapor le 03-06-2013 à 18:47:05

---------------
Perhaps you don't deserve to breathe
n°2192713
theshockwa​ve
I work at a firm named Koslow
Posté le 04-06-2013 à 14:29:10  profilanswer
 

C'est quoi, ton cas de figure ?
Parce que si c'est pour gérer des ressources, je doute que tu veuilles vraiment "supprimer" ta ressources alors que tu as encore des références dessus. C'est pour faire un mécanisme de reload quand ta donnée sur le disque change ?


---------------
last.fm
n°2192730
Terminapor
I'll see you rise.
Posté le 04-06-2013 à 15:34:50  profilanswer
 

Non, c'est pas une ressource mais simplement une instance qui est un mesh dans une scène.
 
Mais le cas de figure serait peut-être plus clair pour un gestionnaire d'objet d'un jeu :
 
Mettons j'ai 30 000 objets dans un jeu qui soient des ennemis, et un qui soit un joueur.
Les 30 000 ennemis auraient en attribut un pointeur pour savoir qui ils ciblent par exemple (qui est à NULL s'il ne cible personne).
Si jamais le joueur est supprimé, dans ce cas tout les ennemis qui avaient leur pointeur de cible sur le joueur sera automatiquement mit à NULL.
 
En gros, si j'ai bien compris ce genre de système est faisable avec les std::shared_ptr / std::weak_ptr :  
 
Chaque ennemi aurait un weak_ptr pour la cible, et le gestionnaire d'objet serait une liste de std::shared_ptr, donc si jamais le joueur est supprimé (plus aucun shared_ptr sur lui), normalement tout les weak_ptr seront marqués comme invalide.
 
Mais finalement, je pense opter pour un système uniquement basé sur les shared_ptr, ou alors une classe encapsulant les shared_ptr, qui aurait une info supplémentaire (une variable mis à true si le possesseur de ce pointeur cherche à supprimer la valeur), qui provoquerait automatiquement une remise à zero du shared_ptr qu'elle encapsule (un truc dans le genre, c'est pas encore bien clair dans ma tête :D)
Le soucis, c'est que tout ce système m'inquiète un peu niveau perfs, j'ai peur de finir par avoir un truc très safe, mais très lent.. :/
 


---------------
Perhaps you don't deserve to breathe
n°2192732
theshockwa​ve
I work at a firm named Koslow
Posté le 04-06-2013 à 15:40:52  profilanswer
 

pour ce genre d'évènement que tu décris, je aurais une préférence pour avoir les N ennemis qui ont un pointeur et ne se soucient pas de son passage à NULL, et, plutôt un système d'évènement robuste pour notifier de la disparition de l'entité qu'ils ciblent.


---------------
last.fm
n°2192735
Terminapor
I'll see you rise.
Posté le 04-06-2013 à 15:49:07  profilanswer
 

Ah oui, j'avais pas pensé à ça :D (même si je pense que dans le cas des meshes c'est pas trop possible)
 
Mais pour un tel système, c'est quoi la meilleur technique ? Parce que re-parcourir toute la liste d'objet dès qu'un objet est supprimé pour tenir toutes les instances au courant, c'est un peu lourd :sweat:


---------------
Perhaps you don't deserve to breathe
n°2192741
theshockwa​ve
I work at a firm named Koslow
Posté le 04-06-2013 à 15:59:14  profilanswer
 

Terminapor a écrit :

Ah oui, j'avais pas pensé à ça :D (même si je pense que dans le cas des meshes c'est pas trop possible)

 

Mais pour un tel système, c'est quoi la meilleur technique ? Parce que re-parcourir toute la liste d'objet dès qu'un objet est supprimé pour tenir toutes les instances au courant, c'est un peu lourd :sweat:

 

dans ma boîte, on a un système d'évènement agnostique qui accepte juste une clé. Tu peux t'enregistrer de manière globale ou avec une clé donnée (Edit/précision : c'est un enregistrement actif en fonction des intérêts de ton observer, pas un système de messages pour tout le monde). Ca te fait atterrir dans des ensembles d'observers différents. Du coup, quand tu signales la disparition de ton truc, tu files son identifiant (quitte à ce que ce soit directement le pointeur de la ressource, hein) et du coup, ca ne va notifier que ceux qui sont intéressés par cette clé là ou l'intégralité de ces messages. Ca garde raisonnable le volume d'observers :)

 

Pour ton histoire de mesh, ca me chiffonne tout de même un peu que ce ne soit pas justement une ressource, après, c'est peut-être juste une question de terminologie, hein.


Message édité par theshockwave le 04-06-2013 à 16:03:54

---------------
last.fm
mood
Publicité
Posté le 04-06-2013 à 15:59:14  profilanswer
 

n°2192750
Terminapor
I'll see you rise.
Posté le 04-06-2013 à 16:55:13  profilanswer
 

Mais pour un tel système, faut bien à un moment parcourir les événement, non ?  
Sachant qu'il peut avoir énormément de création / suppression de meshes, ça risque de beaucoup ralentir tout le processus si j'ai des parcours à faire à chaque fois :/
 
Pour ce qui est du mesh, c'est simplement qu'une fois qu'il est viré de la scène, il n'a plus aucune utilité (il sert juste à être dessiné par la scène elle-même), donc dès lors que la scène le supprime, vaut mieux libérer direct la mémoire, non ?  
Au pire, c'est qu'une petite classe d'environ 200 octets, mais bon :D


---------------
Perhaps you don't deserve to breathe
n°2192752
theshockwa​ve
I work at a firm named Koslow
Posté le 04-06-2013 à 17:13:32  profilanswer
 

J'ai tendance à partir dans l'optique inverse : ton mesh est une ressource, si ton manager de meshes s'aperçoit qu'il est le seul à avoir des références sur un mesh donné, alors il peut le détruire, sinon, c'est que quelqu'un a besoin de le rendre. Je trouve surprenant de garder un pointeur sur une donnée graphique si c'est pas pour qu'elle soit dans ta scène.
 
Pour en revenir aux évènements à parcourir, à nouveau, je vois mal ce qui peut référencer tes meshes et qui ne te donne pas de contrainte forte sur la durée de vie de ta donnée, mais tpar exemple, tu peux avoir un évènement par type de message (l'annonce de la suppression d'une ressource est un message à part entière), chaque évènement a son propre pool d'observers globaux (qui seront systématiquement notifiés) plus un conteneur associatif clé -> pool d'observers (ici, la clé est un identifiant unique de ta ressource). Tes observers devraient en toute logique être assez peu nombreux, non ?
 
Et sinon, aussi, je ne sais pas si la suppression immédiate est forcément une bonne chose. C'est souvent moins contraignant de partir du principe que tu marques pour suppression et que tu vas éliminer tout ce qui doit l'être à un point bien particulier. Ca t'évite en grande partie de te soucier de multi-threading suivant l'endroit où tu te dis que tel truc ne sera plus utile :)


---------------
last.fm
n°2192765
Terminapor
I'll see you rise.
Posté le 04-06-2013 à 17:51:31  profilanswer
 

Effectivement j'avais pas pensé le problème dans l'autre sens, puisque techniquement si un mesh est supprimé, c'est que l'objet qui le manipule est aussi supprimé.
 
Pour ce qui est du gestionnaire d'événements, c'est une bonne idée ça m'évitera des fonctions de traitements d'événements de partout, faudrait que je check aussi un peu comment le système des QConnect est fat parce que ça peut être très pratique :D
 
Globalement, je verrais tout ça un peu sur le tas, merci pour ton aide ! :)


---------------
Perhaps you don't deserve to breathe

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  Gestion des pointeurs sur instance

 

Sujets relatifs
Gestion des pop-up avec SELENIUMégalité des pointeurs
VBA Gestion de Portefeuille, portefeuille optimal[C] [Résolu] Tetris -> SDL ? Réseaux ?
Upload de fichier + gestion comptes utilisateursGestion de la mémoire / recherche de fuites
[SQL] Requete gestion stock ???Probleme : Tableau de pointeurs sur structure
stage en licence troisième année economie gestion 
Plus de sujets relatifs à : Gestion des pointeurs sur instance


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR