Bonjours a tous,
Pour ce premier post sur developpez.com, je vous propose une class qui tente de répondre au problématiques suivantes:
- Stocker des objets d'un type définie(template)
- Pouvoir récupérer ces objets a l'aide d'une clé(tableau associatif)
- Détruire les objets qui ne sont plus utilisés ailleurs que dans le conteneur
- Et éventuellement créer l'objet demandé si il n'est pas déjà présent dans le conteneur
Concrètement, il s'agit d'un std::map associant une clé template a un boost::weak_ptr<>, avec une fonction "Factory" que l'on peu lui passer.
Une map de shared_ptr n'aurait pas permit le delete, c'est pourquoi j'utilise les weak_ptr, qui sont transformé en shared_ptr lorsqu'ils sont requis.
Avant tout voici le code:
Pour l'exemple, supposons que vous ayez une factory qui vous construise un objet MyObject à partir d'un seul paramètre(pour commencer), disons un int.
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
73
74
75
76
77
78
79
80 #include <boost/weak_ptr.hpp> #include <boost/function.hpp> #include <boost/foreach.hpp> #include <map> namespace Blas { template<class K, class V> class weak_map { typedef std::map<K, boost::weak_ptr<V> > WeakMapType; //Type du conteneur interne typedef typename WeakMapType::iterator iterator; //Type de l'itérateur typedef typename WeakMapType::const_iterator const_iterator; //Type de l'itérateur const typedef boost::function1<boost::shared_ptr<V>, const K&> Factory; //Type de la fonction de la factory WeakMapType _weakMap; //Conteneur Factory _factory; //Fonction factory public: //Constructeur et définition du pointeur sur la factory weak_map(Factory f = 0):_factory(f) { } //Fait un ajout dans le tableau associatif void add(const K &key, const boost::shared_ptr<V> &sptr) { std::pair<iterator, bool> res = _weakMap.insert( std::pair<K, boost::weak_ptr<V> >(key, boost::weak_ptr<V>(sptr))); if(res.second == false) { //Si l'élément existe déjà, il n'a pas été modifié. //Donc il faut le faire, car c'est que le pointeur était NULL // (Ou alors il se passe une chose très étrange...) boost::weak_ptr<V> &wptr = res.first->second; wptr = boost::weak_ptr<V>(sptr); } } //Récupère une ressource. (sinon, ou un shared_ptr NULL) //(Peut renvoyer les exceptions du _factory) boost::shared_ptr<V> get(const K &key) { iterator iter = _weakMap.find(key); if(iter != _weakMap.end()) { //Si on a trouvé l'objet associé à la clé boost::weak_ptr<V> &wptrPtr = iter->second; if(wptrPtr.expired() == false) //Et qu'il n'a pas déjà été détruit return boost::shared_ptr<V>(wptrPtr); } //Si on a pas trouvé l'objet... if(_factory) { //...et qu'une fonction factory a été définie, on l'utilise boost::shared_ptr<V> sptr(_factory(key)); add(key, sptr); return sptr; } //...et que la fonction factory n'est pas définie, on renvoie un shared_ptr NULL return boost::shared_ptr<V>(); } //Renvoie le nombre de ressources encore allouées int getNbUnexpired() const { int count = 0; const_iterator iterEnd = _weakMap.end(); for(const_iterator pairIter = _weakMap.begin(); pairIter != iterEnd; pairIter++) { if(pairIter->second.expired() == false) count ++; } return count; } }; }
Maintenant vous voulez être sur qu'on ne crée pas en double un MyObject identique dans vote code. Mais que cette objet partagé soit détruit lorsqu'il n'est plus utilisé:
Il est a notez que la fonction factory peut très bien être membre d'une class, à condition d'utiliser boost::bind.
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 //Ma factory shared_ptr<MyObject> factory(int); //Mon gestionnaire de ressources weak_map<int, MyObject> objectMap(factory); { //Comme l'objet n'éxiste pas deja, il sera crée shared_ptr<MyObject> obj1 = objectMap.get(586); //Comme il existe deja, il sera juste partagé entre deux shared_ptr shared_ptr<MyObject> obj2 = objectMap.get(586); } //En sortant du scope, les shared_ptr seront détruit, et l'objet aussi.
Au passage, il est tout a fait possible de créer une clef(et donc une factory) avec plusieurs paramètres, en utilisant le boost::tuple. Vous pourrez le voir dans les exemples joints. (Projet code::block/minGW, probablement compilable sur n'importe quel compilo C++ récent, à condition d'inclure boost dans les chemin de recherche des .hpp)
Ceci dit, ma première question est de savoir si vous trouvez une utilité a cette objet. En effet cette objet semble pouvoir résoudre beaucoup de soucie dans mon code, mais à t'il un réel intérêt d'un point de vu général?
Si c'est le cas alors comment pourrait-on l'optimiser?
(oui je sait bien que faire une map de weak_ptr c'est pas optimum^^)
Et aussi auriez vous des suggestion pour élargir ces possibilité?
Enfin, si vous avez des critiques, n'hésitez pas!
Partager